1

EDIT So, I switched from Glassfish to Wildfly and was using EclipseLink 2.5. This code stopped working when I switched, with the below problems. The entity manager was created with resource local transactions for some reason.

I tried lots of things, but when I switched to Hibernate EM everything worked just fine. END EDIT

I'm using Wildfly 10 and Eclipselink JPA to have a simple Stateless EJB save a record to a database. The methods are here:

This bean is marked @Stateless

@POST
@Override
@Consumes({"application/xml", "application/json"})
public void create(Actor entity) {
    L.info("Creating {}", entity);
    super.create(entity);
    L.info("Created");
}

Here is the abstract parent's method:

public void create(T entity) {
    //getEntityManager().getTransaction().begin();
    getEntityManager().persist(entity);
    //getEntityManager().flush();
    //getEntityManager().getTransaction().commit();
}

If I uncomment the transactional code, it works.

If I add the transaction annotation, it does not work.

Like this, it does not work.

Why? I though EJBs got container managed transactions and that this should be auto-committed. Here is my persistence unit definition:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="net.mikeski_auth_war_0.1.0-SNAPSHOTPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:jboss/datasources/PostgresqlDS</jta-data-source>
    <class>entities.Actor</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.weaving" value="false"/>
      <property name="eclipselink.weaving.fetchgroups" value="false"/>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>

I know my entity is good because if I add some to the DB the find methods work, and if I get the transactions right the inserts work. What am I missing?

mikeb
  • 10,578
  • 7
  • 62
  • 120
  • try marking it as @Transactional – Scary Wombat Mar 09 '16 at 01:29
  • Can you post the application context file for transactional annotation – Sanj Mar 09 '16 at 01:32
  • does not work. I tried it on the abstract class' method and on the implementation method and both, as well as `@TransactionManagement(TransactionManagementType.CONTAINER)` on the class – mikeb Mar 09 '16 at 01:32
  • @Sanj - not spring, just jpa – mikeb Mar 09 '16 at 01:32
  • See if getEntityManager().joinTransaction() helps. Also can you post getEntityManager() source – Sanj Mar 09 '16 at 01:54
  • Well, that throws an exception and says it's resource local. How is that if I have declared it like this it's resource local? – mikeb Mar 09 '16 at 02:00
  • ` @PersistenceContext(unitName = "net.mikeski_auth_war_0.1.0-SNAPSHOTPU") private EntityManager em; ` That's my method – mikeb Mar 09 '16 at 02:02
  • I think your transaction demarcation is a bit buggered. You need to add you AT Transactional to your AT Stateless and DI your EJB into your servlet (the one with AT POST method.) – Desorder Mar 09 '16 at 03:42
  • I do not have a servlet, and the transactional annotations are not working becuause I am getting a resource local transactional entity manager – mikeb Mar 09 '16 at 11:30
  • how do you inject the entity manager? – Antonio Mar 09 '16 at 17:13

2 Answers2

1

I would expect that you pass the object to a Stateless EJB, even if that EJB does nothing more than call em.persist for you. Here you are mixing functionalities, you are making the REST do the EJB's work and there may be things that you (and I) don't fully understand yet. Further, the service layer stateless ejb would presumably have other functions in it, so it's certainly not a waste.

@Inject ActorService actorService;

@POST
@Consumes({"application/xml", "application/json"})
public void create(Actor entity) {
    L.info("Creating {}", entity);
    actorService.create(entity);
    L.info("Created");
}

and, presumably:

@Stateless
public class ActorService {
    @Inject private EntityManager em;

    public create(Actor actor) {
        em.persist(actor);
    }
    .. the rest of the actor service layer
}

I think it's more important to understand the expected way to do things than to understand why the unusual isn't working.

Hope this helps.

K.Nicholas
  • 10,956
  • 4
  • 46
  • 66
  • I'm using this setup because that's a Netbeans pattern for generating REST services from entities. They use the @PersistenceContext annotation to create the EM. How would I construct the EntityManager in this case to make it available? – mikeb Mar 09 '16 at 11:29
  • Hi Mikeb, I would say go ahead and use @PersistenceContext in your stateless ejb. Also, yes, I usually use a Resources utility class that produces the PersistenceContext for injection, as is done in all the [Wildfly samples](https://github.com/wildfly/quickstart/blob/10.x/kitchensink/src/main/java/org/jboss/as/quickstarts/kitchensink/util/Resources.java). Also, I think hibernate is much more mature than EclipseLink. – K.Nicholas Mar 09 '16 at 14:23
0

I think injecting the entityManager inside the bean class marked with @Stateless should work.

If you are getting entitymanager in some other class (parent class) try getting it from entityManagerFactory instead of directly injecting it. Are you already doing that in the super class or do you have a getter for injected em.

There could be java ee version issue as discussed in an answer here I think that answer should be helpful.

As such, I agree with Nicholas's inputs about separating responsibilities.

Community
  • 1
  • 1
Atul
  • 2,673
  • 2
  • 28
  • 34
  • OK, so how do I create the entity manager if not from the @PersistenceContext annotation? – mikeb Mar 09 '16 at 11:30
  • @mikeb The link in my answer has the relevant code. Or you can use the approach Nicolas mentions with his sample code using Inject annotation – Atul Mar 09 '16 at 11:46
  • I tried that, too, and it did not work. I switched to Hibernate JPA and everything worked just fine. I guess it's EclipseLink and Wildfly. – mikeb Mar 09 '16 at 12:58