Inject an EJB into JAX-RS (RESTful service)

JavaRestJakarta EeEjbJax Rs

Java Problem Overview


I'm trying to inject a Stateless EJB into my JAX-RS webservice via annotations. Unfortunately the EJB is just null and I get a NullPointerException when I try to use it.

@Path("book")
public class BookResource {

    @EJB
    private BookEJB bookEJB;

    public BookResource() {
    }
    
    @GET
    @Produces("application/xml")
    @Path("/{bookId}")
    public Book getBookById(@PathParam("bookId") Integer id)
    {
        return bookEJB.findById(id);
    }
}

What am I doing wrong?

Here is some information about my machine:

  • Glassfish 3.1
  • Netbeans 6.9 RC 2
  • Java EE 6

Can you guys show some working example?

Java Solutions


Solution 1 - Java

I am not sure this is supposed to work. So either:

Option 1: Use the injection provider SPI

Implement a provider that will do the lookup and inject the EJB. See:

Example for com.sun.jersey:jersey-server:1.17 :

import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;

import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;

/**
 * JAX-RS EJB Injection provider.
 */
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {

    public ComponentScope getScope() {
        return ComponentScope.Singleton;
    }

    public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
        if (!(t instanceof Class)) return null;

        try {
            Class c = (Class)t;
            Context ic = new InitialContext();

            final Object o = ic.lookup(c.getName());

            return new Injectable<Object>() {
                public Object getValue() {
                    return o;
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

Option 2: Make the BookResource an EJB

@Stateless
@Path("book")
public class BookResource {

    @EJB
    private BookEJB bookEJB;

    //...
}

See:

Option 3: Use CDI

@Path("book")
@RequestScoped
public class BookResource {

    @Inject
    private BookEJB bookEJB;

    //...
}

See:

Solution 2 - Java

This thread is rather old, nevertheless i fought the same problem just yesterday. Here is my solution:

Just make the BookResource a managed bean through @javax.annotation.ManagedBean at class level.

For this to work you need to enable CDI with a beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

This file needs to be in WEB-INF if the BookResource is part of a war file. If the BookResource is packaged with the ejbs put it into META-INF.

If you want to use @EJB you're done. If you want to inject the EJB through @Inject than a beans.xml must be put into the ejbs jar file into META-INF as well.

What you're doing: You're just telling the container that the resource should be container managed. Therefor it supports injection as well as lifecycle events. So you have your business facade without promoting it to an EJB.

You don't need to extend javax.ws.rs.core.Application for this to work. BookResource is as a root resource automatically request scoped.

Tested with Glassfish 3.1.2 and a maven project.

Happy coding.

Solution 3 - Java

You shall be able to do injection in JAX-RS resource without making it EJB or CDI component. But you have to remember that your JAX-RS resource must not be singleton.

So, you setup your application with this code. This makes BookResource class per-request JAX-RS resource.

@javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
  private Set<Object> singletons = new HashSet<Object>();
  private Set<Class<?>> classes = new HashSet<Class<?>>();
        
  public InjectionApplication() {
    // no instance is created, just class is listed
    classes.add(BookResource.class);
  }
        
  @Override
  public Set<Class<?>> getClasses() {
    return classes;
  }
        
  @Override
  public Set<Object> getSingletons() {
    return singletons;
  }
}

With this setup, you are letting JAX-RS to instantiate BookResource for you on per-request basis and also inject all the required dependencies. If you make BookResource class singleton JAX-RS resource, this is, you put in getSingletons

public Set<Object> getSingletons() {
  singletons.add(new BookResource());
  return singletons;
}

then, you created instance which is not managed by JAX-RS runtime and nobody in container cares to inject anything.

Solution 4 - Java

Unfortunately, my answer is too long for a comment, so here goes. :)

Zeck, I hope that you are aware of what exactly you are doing by promoting your bean to an EJB, as suggested by Pascal. Unfortunately, as easy as it is nowadays with Java EE to 'make a class an EJB', you should be aware of the implications of doing so. Each EJB creates overhead along with the additional functionality it provides: they are transaction aware, have their own contexts, they take part in the full EJB life cycle, etc.

What I think you should be doing for a clean and reusable approach is this: extract the access to your servers services (which hopefully are accessed through a SessionFacade :) into a BusinessDelegate. This delegate should be using some kind of JNDI lookup (probably a ServiceLocator - yes, they are still valid in Java EE!) to access your backend.

Okay, off the record: if you really, really, really need the injection because you do not want to write JNDI access manually, you could still make your delegate an EJB, although it ... well, it just feels wrong. :) That way at least it will be easy to replace it later with something else if you do decide to switch to a JNDI lookup approach...

Solution 5 - Java

I was trying to do the exact same thing. I'm using EJB 3.1 and have a deployed my app as an EAR with separate EJB project. As Jav_Rock pointed out, I use context lookup.

@Path("book")
public class BookResource {

  @EJB
  BookEJB bookEJB;

  public BookResource() {
    try {
        String lookupName = "java:global/my_app/my_ejb_module/BookEJB";
        bookEJB = (BookEJB) InitialContext.doLookup(lookupName);
    } catch (NamingException e) {
        e.printStackTrace();
    }
  }

  @GET
  @Produces("application/xml")
  @Path("/{bookId}")
  public Book getBookById(@PathParam("bookId") Integer id) {
    return bookEJB.findById(id);
  }
}

See the link below for very useful JNDI look up tips

JNDI look up tips

Solution 6 - Java

Arjan is right. I created another class to initialize the EJB instead of creating a bean for RS

@Singleton
@LocalBean
public class Mediator {
    @EJB
    DatabaseInterface databaseFacade;

to avoid null pointer with:

@Path("stock")
public class StockResource {
    @EJB
    DatabaseInterface databaseFacade;
...

it actually works on GF

Solution 7 - Java

I have the same problem, and I solved it calling te EJB by a context lookup (the injection was impossible, I had the same error NullPointerException).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZeckView Question on Stackoverflow
Solution 1 - JavaPascal ThiventView Answer on Stackoverflow
Solution 2 - JavaMichael SimonsView Answer on Stackoverflow
Solution 3 - JavaMartinView Answer on Stackoverflow
Solution 4 - JavaLeCheView Answer on Stackoverflow
Solution 5 - JavaduvoView Answer on Stackoverflow
Solution 6 - JavaLukasz RonikierView Answer on Stackoverflow
Solution 7 - JavaNIkoasView Answer on Stackoverflow