I have a basic JAXRS service that I can expose easily, but for once I wish to use a dependency injection API and I suspect Google Guice will be one of the best. With this in mind, I have tried to integrate it, but the documentation is a little heavy going and I've been having to hunt around to try and find the right combination of
But currently I get errors from Google Guice and they change based on whether I use the @InjectParam annotation or not.
If I annotate with @InjectParam then I get
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
If I don't annotate then I get
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
This is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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/web-app_3_0.xsd">
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.hillingar.server.ServletContextListener</listener-class>
</listener>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
This is my 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/* i.e. ...
*
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
*/
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);
}
});
}
}
This is my 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<User> test(@Context HttpServletRequest hsr) {
// USER DAO IS ALWAYS NULL - CONSTRUCTOR INJECTION NOT WORKING
User loggedInUser = userDao.findBySessionId(hsr.getSession().getId());
...
return users;
}
}
Use of Google Guice for implementing dependency injection in application is very easy and it does it beautifully. It's used in Google APIs so we can assume that it's highly tested and reliable code.
Using GuiceIn each of your constructors that need to have something injected in them, you just add an @Inject annotation and that tells Guice to do it's thing. Guice figures out how to give you an Emailer based on the type. If it's a simple object, it'll instantiate it and pass it in.
To use it, annotate the constructor with the @Inject annotation. This constructor should accept class dependencies as parameters. Most constructors will then assign the parameters to final fields. If your class has no @Inject -annotated constructor, Guice will use a public, no-arguments constructor if it exists.
A binding is an object that corresponds to an entry in the Guice map. You add new entries into the Guice map by creating bindings.
Changed the ServletContextListener to
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);
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With