Inyectar un EJB en JAX-RS (servicio RESTful)

Resuelto Zeck asked hace 14 años • 7 respuestas

Estoy intentando inyectar un EJB sin estado en mi servicio web JAX-RS mediante anotaciones. Lamentablemente, el EJB es justo nully aparece un mensaje NullPointerExceptioncuando intento usarlo.

@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);
    }
}

¿Qué estoy haciendo mal?

Aquí hay información sobre mi máquina:

  • Pez de cristal 3.1
  • Netbeans 6.9 RC 2
  • JavaEE6

¿Pueden mostrar algún ejemplo práctico?

Zeck avatar Jun 12 '10 14:06 Zeck
Aceptado

No estoy seguro de que esto funcione. Entonces cualquiera de las dos:

Opción 1: utilizar el proveedor de inyección SPI

Implemente un proveedor que realice la búsqueda e inyecte el EJB. Ver:

  • Inyección @EJB .

Ejemplo de 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;
        }
    }
}

Opción 2: convertir BookResource en un EJB

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

    @EJB
    private BookEJB bookEJB;

    //...
}

Ver:

  • Cómo combinar servicios REST con EJB 3.1
  • EJB 3.1 y REST: el híbrido ligero

Opción 3: usar CDI

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

    @Inject
    private BookEJB bookEJB;

    //...
}

Ver:

  • Inyectar un EJB desde un frasco en una clase jax-rs en una guerra
Pascal Thivent avatar Jun 12 '2010 15:06 Pascal Thivent

Este hilo es bastante antiguo, sin embargo ayer tuve el mismo problema. Aquí está mi solución:

Simplemente convierta BookResource en un bean administrado a través de @javax.annotation.ManagedBean a nivel de clase.

Para que esto funcione necesitas habilitar CDI con 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>

Este archivo debe estar en WEB-INF si BookResource es parte de un archivo war. Si BookResource está empaquetado con ejbs, colóquelo en META-INF.

Si desea utilizar @EJB, ya está. Si desea inyectar el EJB a través de @Inject, también debe colocar beans.xml en el archivo jar ejbs en META-INF.

Qué estás haciendo: simplemente le estás diciendo al contenedor que el recurso debe ser administrado por contenedor. Por lo tanto, admite la inyección y los eventos del ciclo de vida. Así tendrás la fachada de tu negocio sin promocionarlo a un EJB.

No es necesario ampliar javax.ws.rs.core.Application para que esto funcione. BookResource tiene un alcance de solicitud automático como recurso raíz.

Probado con Glassfish 3.1.2 y un proyecto maven.

Feliz codificación.

Michael Simons avatar Oct 12 '2012 08:10 Michael Simons

Podrá realizar inyección en el recurso JAX-RS sin convertirlo en componente EJB o CDI. Pero debe recordar que su recurso JAX-RS no debe ser singleton.

Entonces, configura su aplicación con este código. Esto hace que la clase BookResource sea un recurso JAX-RS por solicitud .

@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;
  }
}

Con esta configuración, está permitiendo que JAX-RS cree una instancia de BookResource por usted y también inyecte todas las dependencias requeridas. Si crea un recurso JAX-RS singleton de la clase BookResource , es decir, coloca getSingletons

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

luego, creó una instancia que no está administrada por el tiempo de ejecución de JAX-RS y a nadie en el contenedor le importa inyectar nada.

Martin avatar Mar 07 '2012 17:03 Martin