EntityManager null - running JBoss, EJB3, initiated by Web Service
Hi,
I'm having an issue deploying to JBoss 4.0.5-ejb3. When I try to inject my EntityManager in my code: @PersistenceContext EntityManager em;
it is always null.
However, if I do:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("unitName");
em = emf.createEntityManager();
Where unitName is the persistence unit defined in my persistence.xml file - I get an entityManager instance. But I want it all handled by JBoss.
This is my setup:
I have a java web service that calls my Stateless Session bean. In my session bean, I try to inject the PersistenceContext, so I can utilize my Entity Beans.
I have a .ear archive - with a .war (that contains my web service) and a .jar that contains my beans (entity and session).
I have everything annotated according to the documentation and nothing special in my persistence.xml file, besides the <jta-data-source>. All of the documentation says that it should work.
I wrote a client that calls the web service (Axis 1.3 client generated). It calls the service fine, but I get a NullPointerException when it tries to call the em.persist() method inside my stateless session bean.
Any ideas? If I need to provide more information I can.
Thanks,
Bryan
# 1
@PersistenceContext (unitName="your_unitName")EntityManager em;
# 2
Yeah - sorry that wasn't as clear as I thought it was. In my persistence.xml file I have it named "myApp". And then for the Injection I do
@PersistenceContext (unitName="myApp") EntityManager em;
I just put "unitName" as a generic name and it doesn't work.
# 3
Did you put that em annotated line outside of any method, at the class level?
# 4
Yes - I'm sorry again. Let me put as much of my code as possible.
ISampleClass is the @Local Interface class.
@Stateless (name="SampleClass")
public class SampleClass implements ISampleClass
@PersistenceContext (unitName="myDS")
EntityManager em;
public Resource findResource() {
Resource resource = em.find(Resource.class, 1);
return resource;
}
}
<persistence.xml>
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="myDS">
<jta-data-source>java:/myDS</jta-data-source>
</persistence-unit>
And I have a webservice defined that calls the SampleClass method. So I figured even if I have a test client out of the container making the service call - the webservice and the SampleClass are all in the container, so the PersistenceContext should be managed by the container.
But I get a NullPointerException when it tries the find(). (However I don't get the NPE when I initialize with:
emf = Persistence.createEntityManagerFactory("myDS");
em = emf.createEntityManager();
which doesn't make any sense to me because it's looking for the same unitName in each place. And everything is running inside JBoss because the webservice initiates everything. And I'm running JBoss for EJB3 that I just downloaded a week ago using the jems-installer - so that should all be the latest version.
And looking at the JBoss logs with debug on I see this (which seems to me that it's loading correctly):
2007-04-20 09:31:26,390 DEBUG [org.hibernate.ejb.Ejb3Configuration] Processing PersistenceUnitInfo [
name: myDS
persistence provider classname: org.hibernate.ejb.HibernatePersistence
classloader: org.jboss.mx.loading.UnifiedClassLoader3@174a144{ url=file:/C:/jboss-4.0.5.GA/server/default/tmp/deploy/tmp30571MyEAR.ear ,addedOrder=47}
Temporary classloader: null
excludeUnlistedClasses: false
JTA datasource: org.jboss.resource.adapter.jdbc.WrapperDataSource@4eb98b
Non JTA datasource: null
Transaction type: JTA
PU root URL: file:/C:/jboss-4.0.5.GA/server/default/tmp/deploy/tmp30571MyEAR.ear-contents/MyJAR.jar
Jar files URLs []
Managed classes names [ <list of my classes>]
Mapping files names []
Properties [
hibernate.jacc.ctx.id: MyJAR.jar
hibernate.jndi.java.naming.factory.initial: org.jnp.interfaces.NamingContextFactory
hibernate.transaction.manager_lookup_class: org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.cache.provider_class: org.hibernate.cache.HashtableCacheProvider
hibernate.dialect: org.hibernate.dialect.MySQLInnoDBDialect
hibernate.bytecode.use_reflection_optimizer: false
hibernate.jndi.java.naming.factory.url.pkgs: org.jboss.naming:org.jnp.interfaces
hibernate.bytecode.provider: javassist]
Thanks for your patience in helping.
# 5
>
> persistence-unit name="myDS">
> <jta-data-source>java:/myDS</jta-data-source>
> </persistence-unit>
>
Maybe your persistence-unit configuration is incomplete?
If you're not using the default data source (java:/DefaultDS), I think you have to specify your datasource in a *-ds.xml file.
2007-04-20 09:31:26,390 DEBUG [org.hibernate.ejb.Ejb3Configuration] Processing PersistenceUnitInfo [
name: myDS
Also, the persistence-unit configuration typically has a <properties/> tag that refs Hibernate, since the latter is JBOSS's implementation of EJB 3.0 & JTA..
# 6
Yes, I'm using mysql - so I have a mysql-ds.xml file. I also have mysql-connector-java-3.1.13-bin.jar in my jboss server/default/lib.
<datasources>
<local-tx-datasource>
<jndi-name>myDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/myDB</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>myuser</user-name>
<password>mypass</password>
<connection-property name="socketFactory">com.mysql.jdbc.NamedPipeSocketFactory</connection-property>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources
I also did try using multiple different properties for the persistence-unit configuration, but then I figured I'd put in as little as possible - figuring maybe the default values would work.
><persistence-unit name="myDS">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/myDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="validate"></property>
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLInnoDBDialect" />
<property name="hibernate.session_factory_name"
value="java:hibernate/HibernateFactory" />
<property name="transaction.factory_class"
value="org.hibernate.transaction.JTATransactionFactory" />
<property name="hibernate.cache.use_second_level_cache"
value="false" />
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup" />
</properties>
</persistence-unit>
I just looked up a bunch of properties and these are the current ones I just tried (still no success).
It seems to get the EntityManager fine - when I create it using the EntityManagerFactory.createEntityManager("myDS") - which is why I'm so confused.
Is my assumption correct that it should all be container managed with my setup (described in my first post?)
# 7
> It seems to get the EntityManager fine - when I
> create it using the
> EntityManagerFactory.createEntityManager("myDS") -
> which is why I'm so confused.
Not surprising. You can always create the em this way. What's not working here is that the PersistenceContext is not injected.
>Is my assumption correct that it should all be container managed with my >setup (described in my first post?)
As I remember, a container-managed em must be a JTA em. The JTA em would need to share the transaction context of the session bean methods.
So your session bean would need to use JTA.
I believe that, for a session bean, a declarative transaction boundary is enough:
@TransactionType(REQUIRED)
You should of course verify my above statement, as I'm writing this from memory.
# 8
Thanks but it still doesn't seem to be working. I explicity set the transaction-type property in my persistence.xml to "JTA" and I also put
@Stateless(name="SampleClass")
@TransactionAttribute (TransactionAttributeType.REQUIRED)
public class SampleClass implements ISampleClass {}
I also tried setting the TransactionAttribute at the method level with no success.
Some more jboss log information seems to indicate the Hibernate EntityManager is starting and it recognizes myDS.
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] starting service jboss.j2ee:service=EJB3,module=MyApp.jar
2007-04-24 09:00:51,656 DEBUG [org.jboss.ejb3.Ejb3Module] Starting jboss.j2ee:service=EJB3,module=MyApp.jar
2007-04-24 09:00:51,656 DEBUG [org.jboss.ejb3.JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.entity.PersistenceUnitDeployment
2007-04-24 09:00:51,656 INFO [org.jboss.ejb3.JmxKernelAbstraction] installing MBean: persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS with dependencies:
2007-04-24 09:00:51,656 INFO [org.jboss.ejb3.JmxKernelAbstraction] jboss.jca:name=pmacDS,service=DataSourceBinding
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] Creating service persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] adding depends in ServiceController.register: [jboss.jca:name=myDS,service=DataSourceBinding]
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] recording that persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS depends on jboss.jca:name=pmacDS,service=DataSourceBinding
2007-04-24 09:00:51,656 DEBUG [org.jboss.ejb3.ServiceDelegateWrapper] Creating persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS
2007-04-24 09:00:51,656 DEBUG [org.jboss.ejb3.ServiceDelegateWrapper] Created persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] Creating dependent components for: persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS dependents are: []
2007-04-24 09:00:51,656 DEBUG [org.jboss.system.ServiceController] starting service persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS
2007-04-24 09:00:51,656 DEBUG [org.jboss.ejb3.ServiceDelegateWrapper] Starting persistence.units:ear=MyEar.ear,jar=MyApp.jar,unitName=myDS
2007-04-24 09:00:51,671 DEBUG [org.jboss.ejb3.entity.PersistenceUnitDeployment] Found persistence.xml file in EJB3 jar
2007-04-24 09:00:51,687 INFO [org.hibernate.ejb.Version] Hibernate EntityManager 3.2.0.GA
2007-04-24 09:00:51,703 INFO [org.hibernate.cfg.annotations.Version] Hibernate Annotations 3.2.0.GA
2007-04-24 09:00:51,718 INFO [org.hibernate.cfg.Environment] Hibernate 3.2.0.ga
2007-04-24 09:00:51,734 INFO [org.hibernate.cfg.Environment] hibernate.properties not found
2007-04-24 09:00:51,734 INFO [org.hibernate.cfg.Environment] Bytecode provider name : javassist
2007-04-24 09:00:51,734 INFO [org.hibernate.cfg.Environment] using JDK 1.4 java.sql.Timestamp handling
2007-04-24 09:00:51,828 DEBUG [org.hibernate.ejb.Ejb3Configuration] Processing PersistenceUnitInfo [
name: myDS
# 9
I'm afraid I'm running out of ideas at this point....
Have you verified that the injection of a a PersistenceContext works with other type of components (sfsb, eb etc..) ? How about when a simple client (no web services) calls your bean?
Did you also post the problem in a jboss/ hibernate forum? If you didn't, it would be a good idea to do so.
# 10
Ok - so the PersistenceContext is injected when I use a stand-alone client:
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
env.put("java.naming.provider.url", "localhost:1099");
//env.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
InitialContext ctx = new InitialContext(env);
RemoteSampleClass rsc = (RemoteSampleClass)ctx.lookup("MyEar/SampleClass/remote");
rsc.findResource();
So it must be an issue in my stand-alone java client calling my webservice and then my webservice instantiating a SampleClass object.
I'm going to look into if I have to add annotations to my webservice or if there is a special way I have to instantiate my SampleClass from the web service. Because right now I just call the service using Axis generated client code
FindResourceServiceLocator locator = new FindResourceServiceServiceLocator();
FindResourceServicePort port = locator.getFindResourceServicePort();
port.findResource());
then my webservice class just:
public class FindResourceService
{
public String findResource()
{
SampleClass sc = new SampleClass();
return sc.findResource();
}
}
So if you have any input on that - that would be great too. But thank you so much for your help - at least I'm coming closer to some resolution.
# 11
Here is an update:
I was able to inject the PersistenceContext into my session bean by retrieving the LocalInterface class from the InitialContext within my web service java class.
SampleClass sc = null;
InitialContext ic = new InitialContext();
sc = (ISampleClass)ic.lookup("MyEar/SampleClass/local");
I tried injecting the EJB at the class level - but that was always null.
@EJB (mappedName="MyEar/SampleClass/local")
SampleClass sc;
I also tried just setting the mapped name to: SampleClass, MyEar/SampleClass and a bunch of other things - but none of them worked.
Is this the optimal solution to get my web service an instance of my stateless session bean from the container?
# 12
> to inject the PersistenceContext into my
> session bean by retrieving the LocalInterface class
> from the InitialContext within my web service java
> class.
...
> Is this the optimal solution to get my web service an
> instance of my stateless session bean from the
> container?
I don't see a problem with JNDI lookup.
The alternative would be to use JBoss Web services instead of Axis, as the [url=http://jira.jboss.com/jira/browse/EJBTHREE-641?decorator=printable]following comment [/url]on an open bug on JBoss site shows.
It seems that WS implementations other than JBoss WS are unable to get the EntityManager injected via annotation.
# 13
Thanks a lot for your help. I am going to stick with the JNDI lookup in my service. I added it in and it works.Someone replied on the jboss forum about the AS I'm using: http://www.jboss.com/index.html?module=bb&op=viewtopic&t=107353