0

I've been trying to get a hang of Java EE and EJB over the last week.

I've been able to create the entities, DAOs, persistance units and such, but I'm still running into some issues.

In my project, I have an Author and a Book class. These, in turn, have their respective DAOs. (Listed below)

The issue is, my EJBs are being created and added to the JNDI tree correctly, only I can't seem to be able to inject them into my AuthorAPI REST provider... When I call the AuthorAPI.getAllAuthors method, the server responds with a 500 error pointing to the AuthorDAO object being null.

Any help would be greatly appreciated!

TomEE log

INFO: PersistenceUnit(name=libraryPU, provider=org.hibernate.ejb.HibernatePersistence) - provider time 969ms
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=BookDAOLocalBean) --> Ejb(deployment-id=BookDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/BookDAO!org.ucll.rest.dao.BookDAO) --> Ejb(deployment-id=BookDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/BookDAO) --> Ejb(deployment-id=BookDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=AuthorDAOLocalBean) --> Ejb(deployment-id=AuthorDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/AuthorDAO!org.ucll.rest.dao.AuthorDAO) --> Ejb(deployment-id=AuthorDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/AuthorDAO) --> Ejb(deployment-id=AuthorDAO)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=AuthorLocalBean) --> Ejb(deployment-id=Author)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/Author!org.ucll.rest.model.Author) --> Ejb(deployment-id=Author)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/Author) --> Ejb(deployment-id=Author)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=BookLocalBean) --> Ejb(deployment-id=Book)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/Book!org.ucll.rest.model.Book) --> Ejb(deployment-id=Book)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/rest-web/Book) --> Ejb(deployment-id=Book)
dec 21, 2015 2:25:53 PM org.apache.openejb.cdi.CdiBuilder initSingleton
INFO: Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@80169cf
dec 21, 2015 2:25:53 PM org.apache.openejb.cdi.OpenEJBLifecycle startApplication
INFO: OpenWebBeans Container is starting...
dec 21, 2015 2:25:53 PM org.apache.openejb.cdi.OpenEJBLifecycle startApplication
INFO: OpenWebBeans Container has started, it took 19 ms.
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Created Ejb(deployment-id=AuthorDAO, ejb-name=AuthorDAO, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Created Ejb(deployment-id=Book, ejb-name=Book, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Created Ejb(deployment-id=Author, ejb-name=Author, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Created Ejb(deployment-id=BookDAO, ejb-name=BookDAO, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Started Ejb(deployment-id=AuthorDAO, ejb-name=AuthorDAO, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Started Ejb(deployment-id=Book, ejb-name=Book, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Started Ejb(deployment-id=Author, ejb-name=Author, container=Default Stateless Container)
dec 21, 2015 2:25:53 PM org.apache.openejb.assembler.classic.Assembler startEjbs
INFO: Started Ejb(deployment-id=BookDAO, ejb-name=BookDAO, container=Default Stateless Container)

HTTP Status 500 stacktrace

javax.servlet.ServletException: java.lang.NullPointerException
    org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:487)
    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause

java.lang.NullPointerException
    org.ucll.rest.web.api.AuthorAPI.getAllAuthors(AuthorAPI.java:25)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
    org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
    org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471)
    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

Author.java

package org.ucll.rest.model;

import java.io.Serializable;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 *
 * @author larsv
 */
@Entity
@Table(name = "author", schema = "library")
@Stateless
public class Author implements Serializable {
    @Id
    @GeneratedValue
    @Column(name = "id")
    private long id;

    @Column(name = "name", length = 100, nullable = false)
    private String name;

    @OneToMany(mappedBy = "author")
    private List<Book> books;

    public Author() {}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }
}

Book.java

package org.ucll.rest.model;

import java.io.Serializable;
import javax.ejb.Stateless;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 *
 * @author larsv
 */
@Entity
@Table(name = "book", schema = "library")
@Stateless
public class Book implements Serializable {
    @Id
    @GeneratedValue
    @Column(name = "id")
    private long id;

    @Column(name = "title", length = 100, nullable = false)
    private String title;

    @ManyToOne
    @JoinColumn(name = "name")
    private Author author;

    public Book() {}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}

AuthorDAO.java

package org.ucll.rest.dao;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.ucll.rest.model.Author;

/**
 *
 * @author larsv
 */
@Stateless
public class AuthorDAO extends AbstractDAO<Author> {
    @PersistenceContext(unitName = "libraryPU")
    private EntityManager em;

    public AuthorDAO() {
        super(Author.class);
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }
}

BookDAO.java

package org.ucll.rest.dao;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.ucll.rest.model.Book;

/**
 *
 * @author larsv
 */
@Stateless
public class BookDAO extends AbstractDAO<Book> {
    @PersistenceContext(unitName = "libraryPU")
    private EntityManager em;

    public BookDAO() {
        super(Book.class);
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }
}

AuthorAPI.java

package org.ucll.rest.web.api;

import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.ucll.rest.dao.AuthorDAO;
import org.ucll.rest.web.helper.JSONConverter;

/**
 *
 * @author larsv
 */
@Path("/author")
public class AuthorAPI {
    @EJB
    private AuthorDAO authorDAO;

    @GET
    @Path("/all")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllAuthors() {
        String json_response = JSONConverter.covertAuthorList(authorDAO.readAll());
        return Response.status(200).entity(json_response).build();
    }
}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
  <persistence-unit name="libraryPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/library</jta-data-source>
    <class>org.ucll.rest.model.Author</class>
    <class>org.ucll.rest.model.Book</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>
</persistence>

1 Answers1

0

The reason your @EJB is not being resolved is that you are not in the EE container context. The easiest solution for this is to make your webservice an EJB. This can be done by adding the stateless annotation:

@Path("/author")
@Stateless
public class AuthorAPI {

After this change your dao should get injected into it.

On a side note some tips for your code that might help prevent future problems : You should provide a getter/setter method for

private AuthorDAO authorDAO;

Otherwise the container cant inject the implementation at runtime.

On a related note: I dont know what version of EJB you are using but in 3.0 it was necessairy to create an interface for your EJB's. Since 3.1 it is not needed anymore but I still consider it to be best practice to code vs an interface instead of vs an implementation class.

steelshark
  • 644
  • 4
  • 10
  • Thanks for the quick answer! I've refactored the code to work with interfaces in stead of implementation classes and added the setter/getter in my REST API, but this didn't seem to solve the problem. I tried printing out the full JNDI tree, but it seems it is always empty... Any idea as to why this might be? – Lars van Herk Dec 21 '15 at 15:16
  • look at this question:http://stackoverflow.com/questions/3027834/inject-an-ejb-into-jax-rs-restful-service It seems that i looked over the fact that your in a webservice call. You will manualy have to DI in that context – steelshark Dec 21 '15 at 15:25
  • I edited my original answer to include the advice to make your webservice an EJB. This should resolve your problem. – steelshark Dec 21 '15 at 15:30
  • I've looked through that previous question before, it didn't seem to fix the issue. I've tried adding `@Stateless` to the AuthorAPI, but it doesn't seem to fix it either. – Lars van Herk Dec 21 '15 at 16:10
  • `Object bean = ctx.lookup("java:comp/env/org/ucll/rest/dao/impl/AuthorDAO");` does however correctly retreive the bean, so I'm guessing that I'm doing something wrong with my EJB config. – Lars van Herk Dec 21 '15 at 16:12
  • I am surprised that making the webservice a stateless bean did not resolve your problem..I dont have another answer ready for you then..For me personally i avoid EJB and use CDI with Inject and I have very few issues with it – steelshark Dec 21 '15 at 16:19
  • I will try to refactor to CDI based injection, then. Thanks for all your help anyways! If I find a solution I'll be sure to post it here too! – Lars van Herk Dec 21 '15 at 18:30
  • 1
    side note: @ Entity @ Table(name = "author", schema = "library") @ Stateless public class Author implements Serializable { looks weird to. Remove the @ Stateless annotation. An entity is managed by the JPA container and not the EJB container. – struberg Jan 06 '16 at 11:59