EntityManager injection results in NullPointerException
I'm writing my first Java EE (EJB + Servlets etc.) application (please note: I'm using Eclipse).
I'm stuck with a problem with EntityManager injection not working, and having some difficulties finding why due to my Java EE (and Java in general) noobness.Here is my persistence.xml
file - I think this is mostly correct, since I can launch the HSQL database manager from the JMX console and my PUBLIC.USER table shows up correctly.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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">
<persistence-unit name="MyPu">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
开发者_运维问答 <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>
Here's my servlet code:
[...]
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
String id = request.getParameter("username");
String password = request.getParameter("password");
UserManagerBean um = new UserManagerBean();
um.register(username, password);
RequestDispatcher dispatcher=getServletContext().getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response);
}
And here's my UserManagerBean Class:
//bunch of imports
import myPackage.UserManager;
public @Stateful class UserManagerBean implements UserManager {
@PersistenceContext(unitName="MyPu")
private EntityManager persistManager;
public void register(String username, String password) {
User user = new User(userame, password);
persistManager.persist(user);
persistManager.flush();
}
}
The persistManager.persist(user)
line throws a NullPointerException.
From my own searching I understood that this is happening because, since I'm calling new() on UserManagerBean the injection from the @PersistenceContext
annotation never takes place and persistManager never gets bound.
Additional info:
I changed code in my servlet, fromUserManagerBean um = new UserManagerBean();
to
@EJB
private UserManagerBean um;
in the appropriate place. Now um
is the NullPointer.
Quoting Referencing EJB3 Session Beans from non-EJB3 Beans from the JBoss documentation:
JBoss Application Server 4.2.2 implemented EJB3 functionality by way of an EJB MBean container running as a plugin in the JBoss Application Server. This had certain implications for application development.
The EJB3 plugin injects references to an EntityManager and @EJB references from one EJB object to another. However this support is limited to the EJB3 MBean and the JAR files it manages. Any JAR files which are loaded from a WAR (such as Servlets, JSF backing beans, and so forth) do not undergo this processing. The Java 5 Enterprise Edition standard specifies that a Servlet can reference a Session Bean through an @EJB annotated reference, this was not implemented in JBoss Application Server 4.2.2.
So even though the Java EE 5 specification stipulates a wider scope of the @EJB
annotation, JBoss 4.2.2 doesn't support it. In fact JBoss 4.2.2 is a transitional version that doesn't claim full Java EE 5 compliance.
Consequently, either:
- Stick with you actual version of JBoss but use a JDNI lookup to get your bean - or -
- Swith to JBoss 5 AS that fully supports the entire Java 5 Enterprise Edition specification (but has horrible startup performances) - or -
- Swith to another Java EE 5 application server like GlassFish v2 (or even v3) or WebLogic 10. I'd go with GFv3.
As Petar Minchev said in the comments above @EJB doesn't work in servlets with JBoss 4.2.
In your WAR (in the WEB-INF directory) you'll need to modify two files:
web.xml:
<ejb-local-ref>
<ejb-ref-name>ejb/UserManager</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home/>
<local>myPackage.UserManager</local>
</ejb-local-ref>
jboss-web.xml:
<?xml version='1.0' encoding='ISO-8859-1'?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd">
<jboss-web>
<ejb-local-ref>
<ejb-ref-name>ejb/UserManager</ejb-ref-name>
<local-jndi-name>[earname]/UserManagerBean/local</local-jndi-name>
</ejb-local-ref>
</jboss-web>
You can then get an instance of your EJB by doing:
UserManagerBean um = (UserManager)new InitialContext().lookup( "java:comp/env/ejb/UserManager" );
As per the comments, it turns out that you indeed are using an appserver which doesn't support it at all -as I expected. To resolve this, you have 3 options:
- Use "good old" XML config files.
- Upgrade the server (there's already a stable 5.1.0).
- Replace the server (I can recommend Glassfish v3 to be the most up-to-date).
To enable dependency injection on your project make sure that you have the file "beans.xml" and it is properly located.
- For WAR packaging the location is src/main/webapp/WEB-INF/
- For JAR and EAR packaging the location is src/main/resources/META-INF/
If you have several maven modules you must have it on each module.
More information about beans.xml
精彩评论