Jersey Dependency Injection

If I use Jersey 1.12 and I have several resource classes and they all need to access some common context, what is the best way to insert a dependency, whether in the constructor for the resource class or in the handler method? Do I need to use an external DI library, or does Jersey have something built-in?

i.e. perhaps the resource for Foos is as follows:

package com.example.resource; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/some/api/path/foo") public class FooResource { @GET @Produces("text/html") public String getFoo(@QueryParam("id") String id) { Foo foo = /* get a Foo from some shared context based on id */ /* Process foo into a String */ } } 

and for bars:

 package com.example.resource; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/some/api/path/bar") public class BarResource { @GET @Produces("text/html") public String getBar(@QueryParam("id") String id) { Bar bar = /* get a Bar from some shared context based on id */ /* Process bar into a String */ } } 
+6
source share
4 answers

I ended up using Google Guice, which is a lightweight DI structure that blends well with Jersey. Here is what I had to do:

First, I added the dependencies in pom.xml:

  <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-guice</artifactId> <version>1.12</version> <scope>compile</scope> </dependency> 

I wanted DAO to be implemented as a singleton interface with an interface:

 public interface MySingletonDao { // ... methods go here ... } 

and specific implementation:

 @Singleton public class ConcreteMySingletonDao implements MySingletonDao { // ... methods go here ... } 

Decorate resource classes as follows:

 @Path("/some/path") @RequestScoped public class MyResource { private final MySingletonDao mySingletonDao; @Inject public MyResource(MySingletonDao mySingletonDao) { this.mySingletonDao = mySingletonDao; } @POST @Produces("application/json") public String post() throws Exception { // ... implementation goes here ... } } 

Created a class that will perform bindings:

 public class GuiceConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new JerseyServletModule() { @Override protected void configureServlets() { bind(MyResource.class); bind(AnotherResource.class); bind(MySingletonDao.class).to(ConcreteMySingletonDao.class); serve("/*").with(GuiceContainer.class); } }); } } 

I used Jetty instead of Glassfish to actually act as a server. In my functional test, it looks something like this:

 private void startServer() throws Exception { this.server = new Server(8080); ServletContextHandler root = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); root.addEventListener(new GuiceConfig()); root.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); root.addServlet(EmptyServlet.class, "/*"); this.server.start(); } 

EmptyServlet comes from the Sunny Gleason example code, issued as an answer at: fooobar.com/questions/85848 / ... - I originally had

 root.addServlet(new ServletHolder(new ServletContainer(new PackagesResourceConfig("com.example.resource"))), "/*"); 

instead of string

 root.addServlet(EmptyServlet.class, "/*"); 

But that made Jersey try and inject dependencies instead of Guice, which caused runtime errors.

+12
source

you can use SingletonTypeInjectableProvider: http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html

:

 ResourceConfig resourceConfig = new DefaultResourceConfig(); resourceConfig.getSingletons().add( new SingletonTypeInjectableProvider<Context, SingletonType>( SingletonType.class, new SingletonType()) {});{code} 

or you can create a descendant of SingletonTypeInjectableProvider, annotate it with @Provider, add it as a class. You can embed the provided instance where you need it and where the standard Jersey injection comes into play.

+3
source

There is a jersey-spring project that supports Spring dependency injection. Replace your sergeant ServletContainer with SpringServlet, add ContextLoaderListener to your web.xml, and you can add beans to your components. Here's a pretty decent walkthrough for setting up

http://www.mkyong.com/webservices/jax-rs/jersey-spring-integration-example/

EDIT

Here is an idea that does not require adding any dependencies. Create your own ServletContextListener that will add your objects to the ServletContext. Then enter the ServletContext in your resources

 public class MyContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent event) { } @Override public void contextInitialized(ServletContextEvent event) { ServletContext context = event.getServletContext(); context.setAttribute(Foo.class.getName(), new FooImpl()); } } 

Then in your resource

 @Path("blah") public class MyResource { private Foo foo; public MyResource(@Context ServletContext context) { foo = (Foo) context.getAttribute(Foo.class.getName()); } } 
+1
source

You do not need to use an external library if you do not want to. It is well documented that getting a CDI to work properly with Jersey is currently a pain. However, from experience I can say that this can be done by doing it myself. It has been some time since I jumped over these hoops, but I seem to recall that we needed to get our Stateless EJB resources to make it work. There may be other steps that I have taken, but I do not remember them now.

When Jersey 2.0 comes out, it should be a lot easier as they switch to using Core CDI instead of their own. See this error for more information:

http://java.net/jira/browse/JERSEY-517

+1
source

Source: https://habr.com/ru/post/916509/


All Articles