0 Replies Latest reply on Sep 20, 2007 7:59 AM by Jonas Carlbaum

    [AS 4.2.1] Persistence, EntitManager and dependency injectio

    Jonas Carlbaum Newbie

      Hi!

      We have experienced a problem in JBoss AS 4.2.1 GA.

      We have succeeded in manager.createQuery(...).getResultList(); but only when forced to instantiate the EntityManager using EntityManagerFactory.

      We have failed in using manager.persist(Object);.

      Although we have created a workaround - that appears ugly in our eyes - since we wish to use code as nicely stated in the standard EJB3-specification - and obvoiusly many of you have succeeded in implementing and deploying those EJB3s.

      Our workaround is to lookup UserTransaction and then our persistence works - persisting our Enterprise entity persists also its contact information, that is isolated in the Contact entity - so we belive that our entity beans are correct, and the persistence annotations also. We haven't encountered any problem is retrieving data.

      @PersistenceContext(unitName="xyz") EntityManager manager;

      When using the above annotations - the persist attempt results in console output that the instance of EnterpriseManager is null - in other words a NullPointerException of the EntityManger is thrown.
      As we wrote on top of this message we were forced to instantiate the EntityManager using EntityManagerFactory as follows:
      private EntityManagerFactory factory = Persistence.createEntityManagerFactory("xyz");
       private EntityManager manager = factory.createEntityManager();


      We have been considering if there could possibly be a deployment issue, or if it is a JBoss AS/EJB3 settings issue.

      The JBoss AS 4.2.1 GA is almost equal to standard installation - only jmx-console password is changed.

      We are using MySql 5 - and it's a InnoDB dialect in the database.

      Since EntityManager seems to work when retrieving data from the database - but not in persisting - we obvously start thinking that it might be related to our datasources and database drivers and setting etc.

      To prevent that you have to ask us for more information instead of help guiding us to the right path with our problem - we provide as much information as we think is needed.

      In the META-INF we have persistence.xml
      <persistence>
       <persistence-unit name="xyz">
       <jta-data-source>java:jdbc/XYZDS_XA</jta-data-source>
       <properties>
       <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
       <property name="hibernate.hbm2ddl.auto" value="none"/>
       <property name="hibernate.show_sql" value="true" />
       <property name="format_sql" value="true"/>
       <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> </properties>
       </persistence-unit>
      </persistence>
      


      In the servers/default/deploy we have xyz-xa-ds.xml(we have tried both local-tx-datasource and tx-datasource):
      <datasources>
       <xa-datasource>
       <jndi-name>jdbc/XYZDS_XA</jndi-name>
       <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
       <xa-datasource-property name="URL">jdbc:mysql://localnetwordcomputername:3306/xyz</xa-datasource-property>
       <user-name>username</user-name>
       <password>password</password>
       <max-pool-size>5</max-pool-size>
       <min-pool-size>0</min-pool-size>
       <blocking-timeout-millis>2000</blocking-timeout-millis>
       <idle-timeout-minutes>2</idle-timeout-minutes> <track-connection-by-tx>true</track-connection-by-tx>
       <new-connection-sql>set autocommit=1</new-connection-sql>
       <no-tx-separate-pools>true</no-tx-separate-pools>
      
       <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
       <metadata>
       <type-mapping>mySQL</type-mapping>
       </metadata>
       </xa-datasource>
      </datasources>
      


      Our service that we use is a Stateless EJB3:
      EnterpriseService.java
      package org.xyz.services;
      
      import java.util.ArrayList;
      import java.util.Collection;
      import java.util.List;
      
      import javax.ejb.Stateless;
      import javax.ejb.TransactionManagement;
      import javax.ejb.TransactionManagementType;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import javax.persistence.EntityManager;
      import javax.persistence.EntityManagerFactory;
      import javax.persistence.Persistence;
      import javax.persistence.PersistenceContext;
      import javax.transaction.Status;
      import javax.transaction.UserTransaction;
      
      import org.xyz.dao.Contact;
      import org.xyz.dao.Enterprise;
      import org.xyz.dao.IEnterpriseService;
      import org.xyz.dao.User;
      
      @Stateless
      @TransactionManagement(TransactionManagementType.CONTAINER)
      public class EnterpriseService implements IEnterpriseServiceLocal
      {
      // @PersistenceContext(unitName="xyz") EntityManager manager;
       private EntityManagerFactory factory = Persistence.createEntityManagerFactory("xyz");
       private EntityManager manager = factory.createEntityManager();
       private UserTransaction usertransaction = null;
      
       private final static boolean useStandardEJB3 = true;
      
       private void initUserTransaction()
       {
       try
       {
       Context context = new InitialContext();
       usertransaction = (org.jboss.tm.usertx.client.ServerVMClientUserTransaction)context.lookup("UserTransaction");
       }
       catch(NamingException ne)
       {
       ne.printStackTrace();
       }
       }
      
       private Object persist(Object o) throws Exception
       {
       if( useStandardEJB3 )
       {
       if(o instanceof ArrayList)
       {
       for(Object o2:(ArrayList)o)
       manager.persist(o2);
       }
       else
       manager.persist(o);
       return o;
       }
       else
       {
       boolean succeed=false;
       if(usertransaction == null)
       initUserTransaction();
       try {
       usertransaction.begin();
      
       if(o instanceof ArrayList)
       {
       for(Object o2:(ArrayList)o)
       manager.persist(o2);
       }
       else
       manager.persist(o);
       }
       catch (Exception e)
       {
       usertransaction.setRollbackOnly(); // Force a rollback for this error
       throw e;
       }
       finally
       {
       if (usertransaction.getStatus() == Status.STATUS_ACTIVE)
       {
       usertransaction.commit();
       succeed=true;
       }
       else
       {
       usertransaction.rollback();
       succeed=false;
       }
       }
       if(succeed)
       return o;
       else
       return null;
       }
       }
      
       public User login(String username, String password)
       {
       List<? extends User> results = (List<? extends User>) manager.createQuery(
       "SELECT u FROM User u WHERE u.username = :username AND u.password = :password")
       .setParameter("username", username)
       .setParameter("password", password).getResultList();
       if (results.isEmpty())
       {
       return null;
       }
       else
       {
       return results.get(0);
       }
       }
      
       public Enterprise getEnterprise(int id)
       {
       return manager.find(Enterprise.class, id);
       }
      
       public Collection getEnterprises()
       {
       return manager.createQuery("SELECT e FROM Enterprise e")
       .getResultList();
       }
      
       public Collection getEnterprisesByType(String type)
       {
       return manager.createQuery(
       "SELECT e FROM Enterprise e JOIN e.types t WHERE t.name = :type")
       .setParameter("type", type)
       .getResultList();
       }
      
       public Enterprise createEnterprise(Enterprise enterprise)
       {
       try {
       return (Enterprise)persist(enterprise);
       } catch (Exception e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       return null;
       }
       }
      
       public Enterprise updateEnterprise(Enterprise enterprise)
       {
       manager.merge(enterprise);
       manager.flush();
       return enterprise;
       }
      
       public Collection getEnterpriseTypes()
       {
       return manager.createQuery("SELECT t FROM EnterpriseType t")
       .getResultList();
       }
      }
      


      We are using a local interface for the Stateless EJB3:
      IEnterpriseServiceLocal.java
      package org.xyz.dao;
      
      import java.util.Collection;
      
      import javax.ejb.Local;
      
      @Local
      public interface IEnterpriseServiceLocal
      {
       public Enterprise getEnterprise(int id);
       public Collection getEnterprises();
       public Collection getEnterprisesByType(String type);
       public Enterprise createEnterprise(Enterprise enterprise);
       public Enterprise updateEnterprise(Enterprise enterprise);
       public Collection getEnterpriseTypes();
       public User login(String username, String password);
      }
      


      We have a some entity beans:
      Enterprise.java
      package org.xyz.dao;
      
      import java.io.Serializable;
      import java.util.Collection;
      
      import javax.persistence.CascadeType;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.JoinTable;
      import javax.persistence.ManyToMany;
      import javax.persistence.OneToOne;
      
      @Entity
      @SequenceGenerator(name = "enterprise_sequence", sequenceName = "enterprise_id_seq")
      public class Enterprise implements Serializable
      {
       private int id;
       private String name;
       private Collection<EnterpriseType> types;
       private Contact contact;
      
       @Id @GeneratedValue(strategy=GenerationType.IDENTITY, generator = "enterprise_sequence")
       public int getId() {
       return id;
       }
       public void setId(int id) {
       this.id = id;
       }
      
       @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false)
       public Contact getContact() {
       return contact;
       }
       public void setContact(Contact contact) {
       this.contact = contact;
       }
      
       public String getName() {
       return name;
       }
       public void setName(String name) {
       this.name = name;
       }
      
       @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
       @JoinTable(inverseJoinColumns = @JoinColumn(name = "enterprisetype_id"))
       public Collection<EnterpriseType> getTypes() {
       return types;
       }
       public void setTypes(Collection<EnterpriseType> types) {
       this.types = types;
       }
      }
      


      Contact.java
      package org.xyz.dao;
      
      import java.io.Serializable;
      
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.SequenceGenerator;
      
      @Entity
      @SequenceGenerator(name = "contact_sequence", sequenceName = "contact_id_seq")
      public class Contact implements Serializable
      {
       private int id;
       private String email;
       private String phone;
       private String cellular;
       private String fax;
       private String streetAddress;
       private String postalCode;
       private String city;
      
       @Id @GeneratedValue(strategy=GenerationType.IDENTITY, generator = "contact_sequence")
       public int getId() {
       return id;
       }
       public void setId(int id) {
       this.id = id;
       }
      
       public String getCellular() {
       return cellular;
       }
       public void setCellular(String cellular) {
       this.cellular = cellular;
       }
      
       public String getCity() {
       return city;
       }
       public void setCity(String city) {
       this.city = city;
       }
      
       public String getEmail() {
       return email;
       }
       public void setEmail(String email) {
       this.email = email;
       }
      
       public String getFax() {
       return fax;
       }
       public void setFax(String fax) {
       this.fax = fax;
       }
      
       public String getPhone() {
       return phone;
       }
       public void setPhone(String phone) {
       this.phone = phone;
       }
      
       public String getPostalCode() {
       return postalCode;
       }
       public void setPostalCode(String postalCode) {
       this.postalCode = postalCode;
       }
      
       public String getStreetAddress() {
       return streetAddress;
       }
       public void setStreetAddress(String streetAddress) {
       this.streetAddress = streetAddress;
       }
      }
      


      and EnterpriseType.java(not used in our tests - it's a ManyToMany enitity - and we leave it out, using an empty Collection - but we thought we could include it here to show anyway)
      package org.xyz.dao;
      
      import java.io.Serializable;
      
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.SequenceGenerator;
      
      @Entity
      @SequenceGenerator(name = "enterprisetype_sequence", sequenceName = "enterprisetype_id_seq")
      public class EnterpriseType implements Serializable
      {
       private int id;
       private String name;
      
       @Id @GeneratedValue(strategy=GenerationType.IDENTITY, generator = "enterprisetype_sequence")
       public int getId() {
       return id;
       }
       public void setId(int id) {
       this.id = id;
       }
      
       public String getName() {
       return name;
       }
       public void setName(String name) {
       this.name = name;
       }
      }
      


      Extra info: our MySql-tables have all got an Auto Increment key, a bigint. And we are using JDK1.5_0_10. We are deploying as a JAR using an build.xml and ANT (nothing special, just includes the META-INF consisting the persistence.xml and the class packages in the JAR-root). We are using JBoss IDE 2.0 beta as IDE.

      This became a long message - hopefully there is someone who is able to support us regarding our problems. A short repetition of our experienced problems is as follows:
      - We could not get EntityManager to work with annotations. (only when using EntityManagerFactory).
      - We can not persist using standard EJB3 annotations for container managed transacions (needed to lookup UserTransaction and use that). Although we could get info from DB (without UserTransaction).
      - We do not know if our datasources are configured correctly.
      - We do not know if there is anything with the deployment that may be wrong.
      - We do not know if we have failed to configure something in JBoss - that is not in the standard configuration.

      We are thankfull for every input and response we can get - please ask for more information if we have left something out - thanks in advance