70 votes

Injecter un EJB dans JAX-RS (Détente de service)

Je suis en train d'injecter un EJB Stateless dans mon JAX-RS webservice via des Annotations. Malheureusement, les EJB est juste null et je reçois NullPointerException quand j'essaie de l'utiliser.

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

Ce que je fais mal?

Voici quelques informations sur ma machine:

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

Pouvez-vous les gars de montrer quelques exemple de travail?

112voto

Pascal Thivent Points 295221

Je ne suis pas sûr que cela est censé fonctionner. Donc, soit:

Option 1: Utilisation de l'injection fournisseur de SPI

Mettre en œuvre un fournisseur qui va faire la recherche et d'injecter de l'EJB. Voir:

Exemple pour com.soleil.jersey:jersey-serveur: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: Faire le BookResource un EJB

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

    @EJB
    private BookEJB bookEJB;

    //...
}

Voir:

Option 3: Utilisation de CDI

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

    @Inject
    private BookEJB bookEJB;

    //...
}

Voir:

14voto

Michael Simons Points 614

Ce fil est assez vieille, néanmoins j'ai combattu le même problème depuis hier. Voici ma solution:

Il suffit de faire le BookResource un bean géré par @javax.annotation.ManagedBean au niveau de la classe.

Pour que cela fonctionne, vous devez activer le CDI avec un 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>

Ce fichier doit être dans WEB-INF si le BookResource est une partie d'un fichier war. Si le BookResource est emballé avec les ejb mettre dans META-INF.

Si vous souhaitez utiliser @EJB vous avez terminé. Si vous voulez injecter de l'EJB via @Inject qu'un beans.xml doit être mis dans le fichier jar ejb dans META-INF ainsi.

Ce que vous faites: Vous êtes tout simplement dire que le conteneur que la ressource doit être gérée par le conteneur. À cet effet, il prend en charge l'injection ainsi que les événements de cycle de vie. Donc, vous avez à votre entreprise de façade sans la promotion d'un EJB.

Vous n'avez pas besoin de s'étendre javax.ws.rs.de base.L'Application pour que cela fonctionne. BookResource est comme une racine de ressources automatiquement la portée de la requête.

Testé avec Glassfish 3.1.2 et d'un projet maven.

Heureux de codage.

10voto

Martin Points 140

Vous serez en mesure de faire de l'injection de JAX-RS de ressources sans en faire EJB ou CDI composant. Mais vous devez vous rappeler que votre JAX-RS ressource ne doit pas être un singleton).

Donc, vous l'installation de votre application avec ce code. Cela rend BookResource classe par demande de JAX-RS ressource.

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

Avec cette configuration, vous laissant JAX-RS pour instancier BookResource pour vous à chaque requête et également injecter toutes les dépendances nécessaires. Si vous faites BookResource classe singleton JAX-RS de ressources, c'est, vous le mettez dans getSingletons

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

ensuite, vous avez créé l'instance qui n'est pas géré par JAX-RS exécution et personne dans le conteneur des soins à injecter quoi que ce soit.

5voto

LeChe Points 760

Malheureusement, ma réponse est trop long pour un commentaire, donc voilà. :)

Zeck, j'espère que vous êtes conscient de exactement ce que vous faites par la promotion de votre haricot à un EJB, comme le suggère Pascal. Malheureusement, même s'il est facile de nos jours avec Java EE "que la classe d'un EJB", vous devez être conscient des implications de le faire. Chaque EJB crée généraux avec les fonctionnalités supplémentaires qu'il fournit: ils sont au courant de la transaction, ont leurs propres contextes, ils prennent part à la pleine EJB cycle de vie, etc.

Ce que je pense que vous devriez faire pour nettoyer et réutilisable approche est ceci: extrait de l'accès à vos serveurs de services (qui, espérons-le, seront accessibles par le biais d'un SessionFacade :) dans un BusinessDelegate. Ce délégué doit être à l'aide de une sorte de recherche JNDI (probablement un ServiceLocator - oui, ils sont toujours valides en Java EE!) pour accéder à votre serveur.

Ok, off the record: si vous avez vraiment, vraiment, vraiment besoin de l'injection parce que vous ne voulez pas écrire JNDI accès manuellement, vous pouvez toujours faire votre délégué un EJB, bien qu'il ... eh bien, il se sent mal. :) De cette façon, au moins il sera facile de le remplacer plus tard avec quelque chose d'autre si vous décidez de passer à une recherche JNDI approche...

0voto

NIkoas Points 1

J'ai le même problème, et je l'ai résolu en appelant te EJB par un contexte de recherche (l'injection a été impossible, j'ai eu la même erreur NullPointerException).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X