1

I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?

I can't figure out what I'm missing that's causing this NPE.

Usage:

@Path("/helloworld")
public class MyController {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String TestRequest() {
        Workflow workflow = new Workflow();
        workflow.setName("test");

        WorkflowService workflowService = new WorkflowService();
        workflowService.save(workflow);

        return "Workflow ID:";
    }
}

My Dao:

@Stateless
public class WorkflowDao {

    @PersistenceContext(unitName = "unit")
    private EntityManager entityManager;

    public int save(Workflow workflow) {
        entityManager.persist(workflow);
        return workflow.getId();
    }
}

My Service:

@Stateless
public class WorkflowService {

    @EJB
    WorkflowDao workflowDao;

    public int save(Workflow workflow) {
        int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
        return id;
    }
}

This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.

Community
  • 1
  • 1
Ben
  • 60,438
  • 111
  • 314
  • 488

2 Answers2

1

WorkflowDao is not an EJB, it's a POJO with a@Stateless annotation. So naturally, injecting it with @EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.

To make WorkflowDao into a full-fledged EJB, besides having a @Stateless or @Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with @Local and @Remote. Please refer to the tutorial for details.

Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.

As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Why is `@Stateless` incorrect? I frequently see that on DAO objects (http://tomee.apache.org/examples-trunk/rest-example/README.html) – Ben Feb 13 '13 at 19:48
  • If I don't use EJB, how do I properly make the Dao available to my service? – Ben Feb 13 '13 at 19:52
  • @Webnet I clarified my answer. It's not that `@Stateless` is wrong, is that it's not _enough_ : the class needs to implement the local/remote interfaces. If you are not planning to use EJBs, the simply instantiate the DAO in your class, don't inject it - or inject it as a POJO, not as an EJB (depending on the framework you're using). The `@EJB` annotation is reserved for injecting _actual_ EJBs – Óscar López Feb 13 '13 at 19:55
1

If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.

I suggest you:

  • Annotate your Jax-RS Resource @Stateless

  • Inject your WorkfloService via @EJB as a member

Implementing a Local or Remote Interface is not necessary anymore

@Path("workflows")
@Stateless
public class WorkFlowResource{
  @EJB
  WorkflowService workflowService;
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String TestRequest() {
    Workflow workflow = new Workflow();
    workflow.setName("test");
    workflowService.save(workflow);
    return "Workflow ID:";
    }

}
kfis
  • 4,739
  • 22
  • 19
  • When you say `Jax-RS Resource` what are you referring to? What about how my Dao is linked with the service? Should that be @EJB or something else? – Ben Feb 13 '13 at 19:59
  • I guess your Class that has the @GET @Produces(MediaType.TEXT_PLAIN) is a JAX-RS Resource – kfis Feb 13 '13 at 20:00
  • I added `@EJB WorkflowService workflowService;` to that `MyController` class instead of instantiating it. It now throws a NPE at `workflowService.save(workflow)`. I have never used @EJB before so I'm trying to figure this out as I go... – Ben Feb 13 '13 at 20:03
  • What is your MyController Class? Do you instantiate it by hand? Like new MyController()? – kfis Feb 13 '13 at 20:11
  • No, this is a jersey application using grizzly. I tried the method you showed above, it says `workflowService.save(workflow)` is null. – Ben Feb 13 '13 at 20:21
  • Okey, I think your main Problem is, that Grizzly is not an JavaEE ApplicationServer and does not support EJB's, If I remember right, Grizzly is just a Servletcontainer. You should use an Applicationserver for supporting EJB's. Move to Glassfish or try different approach like the Spring-Framework, if you really want to Stick with a plain ServletContainer. – kfis Feb 13 '13 at 20:31