2016-03-29 2 views
0

J'ai une classe de sous-ressource qui doit être initialisé avec un paramètre à partir du chemin et qui contient également une référence à un EJB qui doit être injecté.JAX-RS initialize Il n'y avait pas sous-ressource objet disponible pour l'injection

classe de ressources:

@Path("widgets") 
public class MasterResource{ 
    @Inject 
    WidgetBean widgets; 

    @Context 
    ResourceContext rc; 

    @Path("{year}") 
    public WidgetArchives wArchives(@PathParam("year") String year){ 
     return rc.initResource(new WidgetArchiveResource(year)); 
    } 
} 

classe sous-ressource

public class WidgetArchiveResource{ 
    @Inject 
    WidgetBean widgets; 

    public WidgetArchiveResource(String year){ 
     ....code 
    } 

    @GET 
    public String doGet(){ 
     ....code using WidgetBean 
    } 
} 

Quand j'invoque obtenir l'année, je vois l'erreur suivante:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=WidgetBean,parent=WidgetArchiveResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,542790913) 

Je suis nouveau à Java EE. Qu'est-ce que je fais mal?

+0

Essayez d'injecter 'WidgetArchiveResource' et ne pas créer manuellement cette classe avec' new'. Fournissez un constructeur par défaut et définissez l'année à l'aide d'une méthode. Vous pouvez utiliser 'bean-discovery-mode =" all "' dans beans.xml – simdevmon

+0

Ceci est une sorte d'exercice d'apprentissage pour moi. J'ai vu initresource utilisé de cette façon et j'essaie de le comprendre. – KG6ZVP

Répondre

2

La méthode rc.initResource n'a de sens que si vous avez besoin d'injecter des dépendances dans la ressource (par exemple annoté par @Inject). C'est une manière spécifique à JAX-RS d'injecter des dépendances dans un bean. Il est déconseillé dans un environnement JavaEE complet où la méthode préférée pour injecter des dépendances est via CDI. rc.initResource n'injecte pas tous les beans CDI (par exemple @EJB pourrait fonctionner, mais @Inject pas). Par conséquent, dans JavaEE, la meilleure façon de faire ce que vous voulez faire serait d'injecter WidgetArchiveResource dans le parent . Les beans CDI doivent avoir un constructeur sans arguments, mais vous pouvez passer l'année en utilisant setter. Si vous mettez votre resouce maître portée de la demande, il sera recréé pour chaque demande, ce qui rend sans danger pour les demandes simultanées:

@Path("widgets") 
@RequestScoped 
public class MasterResource{ 
    @Inject 
    Instance<WidgetArchiveResource> waResources; 

    @Path("{year}") 
    public WidgetArchives wArchives(@PathParam("year") String year){ 
     WidgetArchiveResource waResource = waResources.get(); 
     waResource.setYear(year); 
     return waResource; 
    } 
} 

En outre, vous devez soit avoir beans.xml dans votre dossier WEB-INF avec bean-discovery-mode="all", ou ajouter explicitement la portée dépend de votre WidgetArchiveResource pour le rendre CDI éligibles:

@Dependent 
public class WidgetArchiveResource { 
    public WidgetArchiveResource() {} // optional no arg constructor 
} 
+0

Y at-il un moyen de le faire sans avoir à instancier un WidgetArchiveResource chaque fois que quelque chose sur le chemin "widgets" est appelé? – KG6ZVP

+0

Vous pouvez lui affecter une plus grande portée. La plus grande portée est '@ ApplicationScoped', ce qui signifie qu'il sera créé une fois et ensuite réutilisé jusqu'à la fin de l'application. Vous pouvez supprimer @Dependent et ajouter '@ ApplicationScoped'. Vous pouvez également marquer 'MasterResource' comme ceci, au lieu de' @ RequestScoped'. Mais attention, vous ne devriez stocker aucun état entre les requêtes REST, c'est pourquoi je recommande '@ RequestScoped' – OndrejM

+0

Il n'y a donc aucun moyen d'utiliser RequestScoped sur le master sans instancier toutes les sous-ressources même si elles ne sont pas utilisées dans la requête? – KG6ZVP