Comment faire fonctionner Google Guice avec JaxRS (Jersey)

J’ai un service JAXRS de base que je peux facilement exposer, mais pour une fois, je souhaite utiliser une API d’dependency injection et je suppose que Google Guice sera l’un des meilleurs. En ayant cela à l’esprit, j’ai essayé de l’intégrer, mais la documentation est un peu lourde et j’ai dû chercher pour trouver la bonne combinaison de

  • Web.xml
  • Écouteur de contexte (dois-je utiliser ServletContainer ou GuiceContainer)
  • Un service
  • Indiquer si le service doit être annoté avec @Singleton ou @Request ou rien (devrais-je annoter avec @Singleton – docs dit que je devrais le faire mais dit ensuite qu’il demande par défaut de définir la scope)
  • Indique s’il faut annoter les parameters du constructeur avec @InjectParam

Mais actuellement, je reçois des erreurs de Google Guice et celles-ci changent selon que j’utilise l’annotation @InjectParam ou non.

Si j’annote avec @InjectParam alors je reçois

Mar 29, 2013 9:52:04 PM com.sun.jersey.spi.inject.Errors processErrorMessages SEVERE: The following errors and warnings have been detected with resource and/or provider classes: SEVERE: The class com.hillingar.server.dao.interfaces.UserDao is an interface and cannot be instantiated. SEVERE: Missing dependency for constructor public com.hillingar.server.SessionUtility(com.hillingar.server.dao.interfaces.UserDao) at parameter index 0 

Si je n’annote pas, alors je reçois

  Mar 29, 2013 9:54:59 PM com.sun.jersey.spi.inject.Errors processErrorMessages SEVERE: The following errors and warnings have been detected with resource and/or provider classes: SEVERE: Missing dependency for constructor public com.hillingar.server.rest.UserService(com.hillingar.server.dao.interfaces.UserDao,com.hillingar.server.SessionUtility) at parameter index 0 SEVERE: Missing dependency for constructor public com.hillingar.server.rest.UserService(com.hillingar.server.dao.interfaces.UserDao,com.hillingar.server.SessionUtility) at parameter index 1 

C’est mon web.xml

     guiceFilter com.google.inject.servlet.GuiceFilter   guiceFilter /*   com.hillingar.server.ServletContextListener    30    

Ceci est mon ServletContextListener

 package com.hillingar.server; import java.util.logging.Logger; import javax.servlet.ServletContextEvent; import com.google.inject.Guice; import com.google.inject.Singleton; import com.hillingar.server.dao.jdbcImpl.UserJdbc; import com.hillingar.server.dao.interfaces.UserDao; import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.spi.container.servlet.ServletContainer; public class ServletContextListener implements javax.servlet.ServletContextListener { Logger logger = Logger.getLogger(this.getClass().getName()); @Override public void contextDestroyed(ServletContextEvent arg0) { } /* * Covered in URL * https://code.google.com/p/google-guice/wiki/ServletModule */ @Override public void contextInitialized(ServletContextEvent arg0) { // Note the user of JerseyServletModule instead of ServletModule // otherwise the expected constructor injection doesn't happen // (just the default constructor is called) Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { /* * Note: Every servlet (or filter) is required to be a * @Singleton. If you cannot annotate the class directly, * you must bind it using bind(..).in(Singleton.class), * separate to the filter() or servlet() rules. * Mapping under any other scope is an error. This is to * maintain consistency with the Servlet specification. * Guice Servlet does not support the * deprecated SingleThreadModel. */ bind(SecurityFilter.class).in(Singleton.class); bind(ServletContainer.class).in(Singleton.class); /* * Filter Mapping * * This will route every incoming request through MyFilter, * and then continue to any other matching filters before * finally being dispatched to a servlet for processing. * */ // SECURITY - currently disabled // filter("/*").through(SecurityFilter.class); /* * Registering Servlets * * This registers a servlet (subclass of HttpServlet) called * ServletContainer, the same one that I would have used in * the web.xml file, to serve any web requests with the * path /rest/* ie ... *  ServletAdaptor com.sun.jersey.spi.container.servlet.ServletContainer 1   ServletAdaptor /rest/*  */ serve("/rest/*").with(ServletContainer.class); // JAX-RS // Using this and it starts bitching about // com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes. // So presumably wants an Application class that enumerates // all my services? //serve("/rest/*").with(GuiceContainer.class); /* * Bindings */ bind(UserDao.class).to(UserJdbc.class); bind(SessionUtility.class); } }); } } 

Ceci est mon UserService

 package com.hillingar.server.rest; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.SecurityContext; import com.hillingar.server.SessionUtility; import com.hillingar.server.dao.interfaces.UserDao; import com.hillingar.server.model.User; import com.hillingar.server.model.dto.AuthenticationResponse; @Path("/user") @Produces("application/json") @Consumes({"application/xml","application/json"}) @Singleton // <-- Added Singleton here public class UserService { private UserDao userDao; private SessionUtility sessionManager; /* Error if I annotate with @InjectParam... Mar 29, 2013 9:52:04 PM com.sun.jersey.spi.inject.Errors processErrorMessages SEVERE: The following errors and warnings have been detected with resource and/or provider classes: SEVERE: The class com.hillingar.server.dao.interfaces.UserDao is an interface and cannot be instantiated. SEVERE: Missing dependency for constructor public com.hillingar.server.SessionUtility(com.hillingar.server.dao.interfaces.UserDao) at parameter index 0 Error If I don't annotate at all... Mar 29, 2013 9:54:59 PM com.sun.jersey.spi.inject.Errors processErrorMessages SEVERE: The following errors and warnings have been detected with resource and/or provider classes: SEVERE: Missing dependency for constructor public com.hillingar.server.rest.UserService(com.hillingar.server.dao.interfaces.UserDao,com.hillingar.server.SessionUtility) at parameter index 0 SEVERE: Missing dependency for constructor public com.hillingar.server.rest.UserService(com.hillingar.server.dao.interfaces.UserDao,com.hillingar.server.SessionUtility) at parameter index 1 (both output Initiating Jersey application, version 'Jersey: 1.13 06/29/2012 05:14 PM') */ @Inject public UserService(UserDao userDao, SessionUtility sessionManager) { this.userDao = userDao; this.sessionManager = sessionManager; } @GET public List test(@Context HttpServletRequest hsr) { // USER DAO IS ALWAYS NULL - CONSTRUCTOR INJECTION NOT WORKING User loggedInUser = userDao.findBySessionId(hsr.getSession().getId()); ... return users; } } 

Changé le ServletContextListener à

 package com.hillingar.server; import java.util.logging.Logger; import javax.servlet.ServletContextEvent; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Singleton; import com.google.inject.servlet.GuiceServletContextListener; import com.hillingar.server.dao.jdbcImpl.UserJdbc; import com.hillingar.server.dao.interfaces.UserDao; import com.hillingar.server.rest.UserService; import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.spi.container.servlet.ServletContainer; // (1) Extend GuiceServletContextListener public class ServletContextListener extends GuiceServletContextListener { Logger logger = Logger.getLogger(this.getClass().getName()); // (1) Override getInjector @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { bind(SecurityFilter.class).in(Singleton.class); bind(UserService.class);// .in(Singleton.class); bind(ServletContainer.class).in(Singleton.class); // (2) Change to using the GuiceContainer serve("/rest/*").with(GuiceContainer.class); // <<<<--- bind(UserDao.class).to(UserJdbc.class); bind(SessionUtility.class); } }); } }