Reputation: 119
I'm developing a Java EE 6 solution and also trying to figure out the root cause of why the dependency injection is not working...NullPointerException inside my service (userDao line):
REST Service
@Path("rest")
public class UserRESTService {
@EJB
UserDAO userDao;
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("{type}")
public String getJqGridData(@PathParam("type") String type) {
System.out.println("type: " + type);
List<USUARIO> usuarios = userDao.findAll();
int pageSize = 10;
int pageNumber = ((int) usuarios.size()/pageSize)+1;
JqGridData<USUARIO> data = new JqGridData<USUARIO>(pageNumber, 1, usuarios.size(), usuarios);
System.out.println("Grid Data: " + data.getJsonString());
return data.getJsonString();
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>MyWeb</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.application.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.writeStateAtFormEnd</param-name>
<param-value>false</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>bch.com.br.service.rest.RESTEasySingleton</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
REST Singleton
public class RESTEasySingleton extends Application
{
private Set<Object> singletons = new HashSet();
private Set<Class<?>> empty = new HashSet();
public RESTEasySingleton() {
this.singletons.add(new UserRESTService());
}
public Set<Class<?>> getClasses()
{
return this.empty;
}
public Set<Object> getSingletons()
{
return this.singletons;
}
}
DAO
@Stateless
public class UserDAO extends BaseDAO<USUARIO>{
@PersistenceContext(unitName="MyJPA")
private EntityManager em;
public UserDAO(Class<USUARIO> entityClass) {
super(entityClass);
}
public UserDAO() {
super(USUARIO.class);
}
@SuppressWarnings("unchecked")
public List<USUARIO> findAll() {
Query q = getEntityManager().createQuery("SELECT e FROM " + USUARIO.class.getName() + " e");
List<USUARIO> list = (List<USUARIO>) q.getResultList();
return list;
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
Although, the injection works fine inside another managed bean...
@ManagedBean
@RequestScoped
@Named
public class UserBean {
public UserBean() {
// TODO Auto-generated constructor stub
}
private List<USUARIO> users = new ArrayList<USUARIO>();
private String name;
@Transient
@EJB
UserDAO userDao;
...
}
Any ideas?
Upvotes: 3
Views: 933
Reputation: 1562
I am just adding an answer because I struggled with the same situation, and couldn't get the knack of it for like a long time. In the above code snippets, while the above suggestion by John Ament is right - it doesn't explain why the injection doesn't work - both web.xml and explicit "RESTEasySingleton extends Application" initialization (that should be mutually exclusive) create a new instance of RESTEasySingleton OUTSIDE the CDI context - the other ManagedBean's simply are unaware of RESTEasySingleton and vice-versa.
As suggested by other answers on similar questions here on stackoverflow, the RESTEasySingleton should be left literally empty to let the CDI container discover it and initialize it in its own context. (RequestScoped would be unnecessary - actually I saw somewhere that all RESTEasy stuff marked with e.g. @Path annotation are @RequestScoped by default)
But in my case this wasn't the only problem. RESTEasySingleton has an annotation @ApplicationPath that should tell what is the root context path of RESTEasy endpoints. Somehow, from some code snippets out there, I wrote it like this : @ApplicationPath("/*") - which must be criminally wrong. Correcting it to @ApplicationPath("/") was all it took to leave me battered but at least a little bit content.
Upvotes: 1
Reputation: 11723
Add @RequestScoped
to your rest endpoint. I would also remove the reference to the resteasy bootstrap in your web.xml, since you're deploying to an EE6 container it's not needed (the application extension is enough).
Upvotes: 2