22

I am learning to use JAX-RS for some restful api development and have an issue regarding my resource classes.

My understanding is that my resource class should be RequestScoped, however, when it is RequestScoped my call to the entity manager's persist method it throws a TransactionRequiredException.

If I change my resource class to be Stateless then everything is fine and the entity manager can persist without any issue.

I am still new to JavaEE and would like to know why this happens and what the @Stateless annotation does that allows the persistence context to inject correctly. I would also like to know if there is any problem with JAX-RS resource classes being stateless instead of RequestScoped as most of the tutorials I've seen have them.

I have included some example code below to illustrate.

@Path("Things")
//@Stateless //works just fine when em.persist() is called
@RequestScoped //throws transactionrequiredexception when em.persist() is called
public class ThingsResource{

    @PersistenceContext(unitName = "persistenceUnitName")
    EntityManager em;


    public ThingsResource() { }

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Response postThing(ThingDTO thing){

        ThingEntity newThing = new ThingEntity(thing);
        em.persist(newThing);
        em.flush();

        return Response.created(new URI("/" + newThing.getId()).build();

    }
}
Bltucker
  • 447
  • 3
  • 9
  • 17
  • 5
    I think if you have a Stateless Bean and you dont use Transaction Annotations e.g (Required), your Applicationserver is going to use Container based Transaction for its ejbs. Request Scoped Beans are within the Servlet Container that does not provide Container based Transaction (i think) – Matthias H Dec 13 '13 at 10:47
  • If you really need a separate state per request (e.g. when binding a path parameter to a field of your class) I would suggest using `@RequestScoped` together with `@Stateful`. Otherwise `@Stateless` will do the job. – Daniel Beer Jul 11 '21 at 06:32

2 Answers2

15

Matthias is spot on.

A @Stateless annotated bean is an EJB which by default provides Container-Managed-Transactions. CMT will by default create a new transaction if the client of the EJB did not provide one.

Required Attribute If the client is running within a transaction and invokes the enterprise bean’s method, the method executes within the client’s transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method.

The Required attribute is the implicit transaction attribute for all enterprise bean methods running with container-managed transaction demarcation. You typically do not set the Required attribute unless you need to override another transaction attribute. Because transaction attributes are declarative, you can easily change them later.

In the recent java-ee-7 tuturial on jax-rs, Oracle has example of using EJBs (@Stateless).

... the combination of EJB's @javax.ejb.Asynchronous annotation and the @Suspended AsyncResponse enables asynchronous execution of business logic with eventual notification of the interested client. Any JAX-RS root resource can be annotated with @Stateless or @Singleton annotations and can, in effect, function as an EJB ..

Main difference between @RequestScoped vs @Stateless in this scenario will be that the container can pool the EJBs and avoid some expensive construct/destroy operations that might be needed for beans that would otherwise be constructed on every request.

Harry
  • 11,298
  • 1
  • 29
  • 43
Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74
  • 1
    So what is bether or what is more efficient regarding the performance? It should be the @Stateless because it is poolable, right? Which drawback does this have on the resouce? - I would be glad if you could include this aspect in your answer - thanks! I already voted up in advance... :) – badera Dec 07 '16 at 06:32
  • I doubt you will see any real life difference with regards to performance here. In theory if construction of the bean is expensive, the pooling will come into play. If you are using EJBs and CMT in your application, use that because code is less verbose – Aksel Willgert Dec 07 '16 at 07:36
6

When you don't want to make your root resource as an EJB (by annotating it with @Stateless), you can use a UserTransaction.

@Path("/things")
@RequestScoped
public class ThingsResource{

    @POST
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Response create(final Thing thing){
        utx.begin();
        em.joinTransaction();
        final ThingEntity thingEntity = new ThingEntity(thing);
        em.persist(thing);
        utx.commit();
        final URI uri = uriInfo.getAbsolutePathBuilder()
            .path(Long.toString(thingEntity.getId())).build();
        return Response.created(uri).build();
    }

    @PersistenceContext(unitName = "somePU")
    private transient EntityManager em;

    @Resource
    private transient UserTransaction ut;

    @Context
    private transient UriInfo uriInfo;
}
Harmelodic
  • 5,682
  • 1
  • 28
  • 31
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184