Using HK2 with Jersey (with auto-scanning!)

Overview

HK2 has been an interesting ride. For the most part, if anyone asks, I’m still going to suggest Spring for Dependency Injection, because the documentation is a thing of wonder. Plus, Spring Inversion of Control (IoC) and Aspect Oriented Programming (AOP) are the wheelhouse that makes all of the other Spring stuff possible.  However, there are some situations where using these technologies are requested/required, so it’s good to know how to use them.

Understanding Dependency Injection

Dependency Injection is a great way to decouple your code from the implementation.  For example, if you create an interface in your core program, and you can leave the implementation for creation in a different library.  How is that useful?  One example of this would be for database access.  If you create a simple interface, like the following:

Now, use this interface in some form of implementation. This should provide a simple passthrough implementation usage of the interface:

You can then make two different implementations that function very differently, and put them in separate jars.

The first could access a database, such as PostgreSQL:

The second implementation could be a MongoDB implementation:

Now for the interesting part… You want it to be able to change at runtime. So your customer can easily change and use PostgreSQL or MongoDB with ease. Heck, they can even add a Redis store with ease and without having to recompile a single line of code. It seems like magic, but it’s not. It’s just smart decoupling.

Using Dependency Injection with Jersey

Jersey, by default uses HK2 (aka Hundred Kilobyte Kernel) for Dependency Injection. This was developed by Oracle for the Glassfish Application Server.  HK2 follows the the JSR-330 specification entirely.  What does that mean? It means that this library can be swapped out for another with ease.  So, if you develop with it, just remember that you can swap it out later.  Unfortunately, with Jersey, they are using HK2 for Dependency Injection, so you are forced to either use it, or bridge it with the Spring Bridge or Guice Bridge (there may be others, but those are the most popular DI libraries right now).

So, regardless of which one you use (HK2, Spring, Guice, etc), you should use be using the standardized JSR-330 annotations.  These are as follows:

JSR-330 Description
@javax.inject.Contract Annotation to identify interfaces that match a component
@javax.inject.Service Annotation to identify components that can be injected – used for scanning
@javax.inject.Inject Inject an instantiated class into an placeholder variable or method
@javax.inject.Named Differentiate between different objects of the same type
@javax.inject.Qualifier Used for annotating new annotations (because named annotations are evil)
@javax.inject.Scope By placing this annotation, you can tell the injector to retain the instance for possible reuse in a later injection
@javax.inject.Singleton Since HK2 defines that everything is a Prototype, this is necessary for a Singleton instance. Please note, this doesn’t apply when using the @Service annotation (which you should be using most of the time anyways), which is a singleton

So, how would we go about annotating these classes for JSR-330? First, identify your interfaces. For a simple example, your interface should be adjusted to look like this:

Next, annotate your implementation classes.

The second implementation could be a MongoDB implementation:

This will tell your program that if it sees the interface DocumentSaver being used with the @Inject, it will create the class identified with the @Service

Lastly, we need to identify where you need these and apply the @Inject annotation. I advise people to use constructor injection, which ensures all mandatory properties have been satisfied, and it is simply not possible to instantiate an object in an invalid state. Plus, it’s significantly easier to test this way. Here’s the augmented DocumentStorage class, identified with @Inject.

Now, depending on whether you are going to use PostgreSQL or MongoDB, you adjust the classpath accordingly. Now, when the system sees the PostgresDocumentSaver class on the classpath, it will save to Postgres, and when it sees MongoDocumentSaver on the classpath, it will save to MongoDB. With something like Maven, you can swap out a dependency jar.

Using HK2 for Dependency Injection

So, when using Spring, you can use the the auto-scan function which automagically wires these classes on the classpath together at startup.  HK2 isn’t quite as easy to work with.  It needs a serialized map of interfaces and services to figure out what to use.  This is done via the Inhabitant Generator.  Following these instructions, you should probably generate them on the fly using your build tool, such as Gradle or Maven.  This will put a file in the META-INF/hk2-inhabitant folder.

If you have a simple application, you can use the following to scan all of these files and then:

and then you can automatically get services with this bit of code:

However, with Jersey, the ServiceLocator has been created and populated already, which means that it gets a little complicated. To remedy this, make the following classes:

These classes will allow you to read in inhabitor files and add them to the existing serviceLocatory. Finally, create your Jersey Application by extending the ResourceConfig:

And Voila! It will automatically scan all of your dependencies and the current WAR for inhabitor files to populate. For anything that you are having issues with, use the “register(…)” section of the ApplicationConfig class to manually bind classes.