开发者

How to handle persistence context (EntityManager) with jax-rs sub-resource locators?

I am using jax-rs restful web service in my application with sub-resource locators. However after passing entityManager to sub-resource I cannot persist any new objects in this sub-resource.

The entityManager lets me however to query it for data.

This is my main resource:

@Path("/registrations")
@Stateless
public class RegistrationsResource {

    @Context
    private UriInfo context;

    @PersistenceContext(unitName="pctx")
    private EntityManager em;

    public RegistrationsResource() {
    }

    //POST method ommited

    @Path("{regKey}")
    public RegistrationResource getRegistrationResource(@PathParam("regKey")
    String regKey) {
        return RegistrationResource.getInstance(regKey, em);
    }

}

And this is my sub-resource:

public class RegistrationResource {

    private String regKey;
    private EntityManager em;

    private RegistrationResource(String regKey, EntityManager em) {
        this.regKey = regKey;
        this.em = em;
    }

    @Path("securityQuestion")
    @GET
    public String getQuestion() {
        return "iamahuman"+regKey;
    }

    @Path("securityQuestion")
    @POST
    public void postSecurityAnswer(String answer) {
        if(!answer.equals("iamahuman"+regKey)){
            throw new WebApplicationException(Status.BAD_REQUEST);
        }

        //Getting this information works properly
        List<RegistrationEntity> result = em.createNamedQuery("getRegistrationByKey")
            .setParameter("regKey", regKey).getResultList();

        switch(result.size()){
            case 0 :
                throw new WebApplicationException(Status.NOT_FOUND);
            case 1:
                break;
            default:
                throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
            }

            RegistrationEntity reg = result.get(0);
            UserEntity newUser = new UserEntity();

            newUser.setHashedPassword(reg.getPwHash(), reg.getSalt());
            newUser.setUsername(reg.getUsername());
            newUser.setName(reg.getName());
            newUser.setSurname(reg.getSurname());

            //CRASHES HERE
            em.pe开发者_JAVA百科rsist(newUser);
    }
}

As you can see it takes registration object from database, creates new user for registration and tries to persist it. However, em.persist(newUser) throws TransactionRequiredException.

My question is: how should I pass EntityManager to sub-resource so it can properly persist new objects?


Sorry for digging this up again, but I suggest the following:

  • Annotate also the sub-resource as a @Stateless EJB
  • Place @EJB injection member fields into the parent resource class, like so:
        @EJB private RegistrationResource registrationResource;
    
  • in "getRegistrationResource()", do not call the constructor of the sub-resource, but return the injected EJB reference:
    public RegistrationResource getRegistrationResource() {
        return this.registrationResource;
    }

For this to work, however, you cannot pass the "@PathParam" as a constructor parameter. You would have to access it seperately in the subresource via the "@Context" or another @Path declaration.
This enables you to inject the EntityManager in the sub resource in exactly the same way as in the parent resource, you don't need to pass it on.


Probably too late but anyway... When you return your sub resource you 'leave' the stateless bean. As the container manages the transaction the transaction is committed when you return from RegistrationsResource.

Jersey will then construct your sub resource but its not a stateless bean so you wont have a container managed transaction. Hence the exception.

I would advice you to put your business logic in a new class which you then make a stateless bean. Here you do all your database stuff which then is always handled in a container managed transaction.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜