Dependency injection with Jersey 2.0
You need to define an AbstractBinder
and register it in your JAX-RS application. The binder specifies how the dependency injection should create your classes.
public class MyApplicationBinder extends AbstractBinder { @Override protected void configure() { bind(MyService.class).to(MyService.class); }}
When @Inject
is detected on a parameter or field of type MyService.class
it is instantiated using the class MyService
. To use this binder, it need to be registered with the JAX-RS application. In your web.xml
, define a JAX-RS application like this:
<servlet> <servlet-name>MyApplication</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.mypackage.MyApplication</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet><servlet-mapping> <servlet-name>MyApplication</servlet-name> <url-pattern>/*</url-pattern></servlet-mapping>
Implement the MyApplication
class (specified above in the init-param
).
public class MyApplication extends ResourceConfig { public MyApplication() { register(new MyApplicationBinder()); packages(true, "com.mypackage.rest"); }}
The binder specifying dependency injection is registered in the constructor of the class, and we also tell the application where to find the REST resources (in your case, MyResource
) using the packages()
method call.
First just to answer a comment in the accepts answer.
"What does bind do? What if I have an interface and an implementation?"
It simply reads bind( implementation ).to( contract )
. You can alternative chain .in( scope )
. Default scope of PerLookup
. So if you want a singleton, you can
bind( implementation ).to( contract ).in( Singleton.class );
There's also a RequestScoped
available
Also, instead of bind(Class).to(Class)
, you can also bind(Instance).to(Class)
, which will be automatically be a singleton.
Adding to the accepted answer
For those trying to figure out how to register your AbstractBinder
implementation in your web.xml (i.e. you're not using a ResourceConfig
), it seems the binder won't be discovered through package scanning, i.e.
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class><init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value> your.packages.to.scan </param-value></init-param>
Or this either
<init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value> com.foo.YourBinderImpl </param-value></init-param>
To get it to work, I had to implement a Feature
:
import javax.ws.rs.core.Feature;import javax.ws.rs.core.FeatureContext;import javax.ws.rs.ext.Provider;@Providerpublic class Hk2Feature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(new AppBinder()); return true; }}
The @Provider
annotation should allow the Feature
to be picked up by the package scanning. Or without package scanning, you can explicitly register the Feature
in the web.xml
<servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value> com.foo.Hk2Feature </param-value> </init-param> ... <load-on-startup>1</load-on-startup></servlet>
See Also:
- Custom Method Parameter Injection with Jersey
- How to inject an object into jersey request context?
- How do I properly configure an EntityManager in a jersey / hk2 application?
- Request Scoped Injection into Singletons
and for general information from the Jersey documentation
UPDATE
Factories
Aside from the basic binding in the accepted answer, you also have factories, where you can have more complex creation logic, and also have access to request context information. For example
public class MyServiceFactory implements Factory<MyService> { @Context private HttpHeaders headers; @Override public MyService provide() { return new MyService(headers.getHeaderString("X-Header")); } @Override public void dispose(MyService service) { /* noop */ }}register(new AbstractBinder() { @Override public void configure() { bindFactory(MyServiceFactory.class).to(MyService.class) .in(RequestScoped.class); }});
Then you can inject MyService
into your resource class.
The selected answer dates from a while back. It is not practical to declare every binding in a custom HK2 binder.I'm using Tomcat and I just had to add one dependency. Even though it was designed for Glassfish it fits perfectly into other containers.
<dependency> <groupId>org.glassfish.jersey.containers.glassfish</groupId> <artifactId>jersey-gf-cdi</artifactId> <version>${jersey.version}</version> </dependency>
Make sure your container is properly configured too (see the documentation).