Search code examples
javadependency-injectionjax-rsjersey-2.0hk2

How to use HK2 DI framkework with Jersey 2?


I am trying to use hk2 DI in jersey and I have read some texts on the matter. (Most are out dated I think) Currently I have a class that extends ResourceConfig:

public class MyApplication extends ResourceConfig{
    public MyApplication(){
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(AuthenticationServiceImpl.class).to(AuthenticationService.class);
                bind(PropertiesHandlerImpl.class).to(PropertiesHandler.class).in(Singleton.class);
            }
        });
        packages(true, "com.myclass");        }
}

and in another class I try to inject one of these bound classes:

public class JDBCConnectionStrategy implements DatabaseConnectionStrategy {
    private Connection connection;

    @Inject
    PropertiesHandlerImpl propertiesHandler;

    public JDBCConnectionStrategy() throws SQLException{
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            String host = propertiesHandler.getProperty("host");
            String userName = propertiesHandler.getProperty("userName");
            String password = propertiesHandler.getProperty("password");
            //Create a connection
            this.connection = DriverManager.getConnection(host, userName, password);
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
....
}

declared thus:

@Singleton
@Service
public class PropertiesHandlerImpl implements PropertiesHandler {...}

Issue: I get the following error when I startup my app

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 2 java.lang.NullPointerException
    at com.myclass.JDBCConnectionStrategy.<init>

Update:
I should add that I added the application package to the scanned path in the web.xml:

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.myclass.system.CmisApplication</param-value>
    </init-param>

Solution

  • So I see a few things wrong.

    1. The injected type needs to be the "contract" type, as in bind(Impl).to(Contract). The to(Contract) specifies what should be the "advertised" type to inject.

      So instead of trying to inject PropertiesHandlerImpl, you would inject with the contract PropertiesHandler

      @Inject
      PropertiesHandler handler;
      
    2. I don't see how you are using the JDBCConnectionStrategy. It's not configured in your AbstractBinder, so I'm guessing you are just instantiating it yourself. This won't work. You need to also hook it up to the DI system and inject it.

    3. Field injection happens after construction. So you can't use the service inside the constructor unless you inject it into the constructor.

      @Inject
      public JDBCConnectionStrategy(PropertiesHandler handler) {
      
      }