Recently I saw a post on a Jersey users mailing list (browse archive) asking for help with injection of a custom component into a Jersey resource. In particular, Jersey supports injection of a SecurityContext
out of the box. Yet, the user wanted to directly inject custom security Principal
rather than invoking the same SecurityContext.getUserPrincipal()
getter all the time.
As you probably know, there is a jersey-guice module that provides a Jersey integration with Google Guice. Using Guice is an easy and elegant way how to extend injectable components in Jersey. Jersey already provided a very basic sample showing how to use Guice which I decided to update and extend to demonstrate how injecting a custom SecurityContext
as well as Principal
can be done.
First I have created a custom SecurityContext
implementation:
public final class MySecurityContext implements SecurityContext { private static final class MyPrincipal implements Principal { @Override public String getName() { return "test-name"; } @Override public String toString() { return "MyPrincipal{" + getName() + '}'; } } @Override public Principal getUserPrincipal() { return new MyPrincipal(); } // ... rest of the code omitted for clarity... } |
To make sure that my custom implementation will get injected and used by Jersey components I had to bind my implementation to the SecurityContext
interface. As described in the jersey-guice module documentation, this can be done by extending and implementing a custom GuiceServletContextListener
class:
public class GuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModule() { @Override protected void configureServlets() { // Bind classes and resources ... bind(SecurityContext.class).to(MySecurityContext.class); ... serve("/*").with(GuiceContainer.class); } }); } } |
This custom servlet context listener is then registered in the web application’s web.xml config file:
<web-app version="2.5" ... > <listener> <listener-class>com.sun.jersey.samples.guice.GuiceServletConfig</listener-class> </listener> ... </web-app> |
Now that I have showed how to inject a custom implementation of the whole SecurityContext
, I will add more code to enable direct injection of Principal
instances. In order to do that I need to create a custom Guice Provider
. I will make it servlet request-scoped to make sure I am injecting proper Provider
instance. The resulting implementation is quite straightforward:
@RequestScoped public final class PrincipalProvider implements Provider<Principal> { private SecurityContext sc; @Inject public PrincipalProvider(SecurityContext sc) { this.sc = sc; } @Override public Principal get() { return sc.getUserPrincipal(); } } |
Now the only remaining thing is to update the custome guice servlet context listener implementation with a new binding:
public class GuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModule() { @Override protected void configureServlets() { // Bind classes ... bind(Principal.class).toProvider(PrincipalProvider.class); bind(SecurityContext.class).to(MySecurityContext.class); serve("/*").with(GuiceContainer.class); } }); } } |
With that, I can now inject the Principal
directly into my Jersey resources. At the same time I can be sure that the my custom implementation of the SecurityContext
will be used:
@Path("bound/perrequest") @RequestScoped public class PerRequestResource { ... private final SingletonComponent sc; private final Principal principal; //Create singleton component and inject into resource at construction as well as principal @Inject public PerRequestResource(SingletonComponent sc, Principal principal) { this.sc = sc; this.principal = principal; } ... } |
For the complete sample code, please download the guicefilter-webapp Jersey sample project.