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.persist(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?
A PersistenceContext is essentially a Cache. It also tends to have it's own non-shared database connection.
An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed.
A subresource locator returns an object that will handle an HTTP request. The method must not be annotated with a request method designator. You must declare a subresource locator within a subresource class, and only subresource locators are used for runtime resource resolution.
Sorry for digging this up again, but I suggest the following:
@EJB private RegistrationResource registrationResource;
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With