Skip to content
This repository has been archived by the owner on Jan 31, 2019. It is now read-only.
Roger edited this page Apr 14, 2016 · 5 revisions

Jersey 2.0 w/ Guice

Introduction

Jersey/HK2 uses unfortunately SPIs and the Singleton pattern internally. Your code is effectively racing against the Servlet container's code and the first one to initialize HK2's ServiceLocatorGenerator inside its ServiceLocatorFactory wins.

This library uses two approaches to override HK2's own ServiceLocatorGenerator. It first tries to use a SPI and if it can't it'll fall back to reflection to replace a private static field. Regardless of the approach it's still a race against the Servlet container.

Simple Example

HK2's ServiceLocators are the equivalent of Guice Injectors. There's one per ApplicationHandler (effectively one per Connector). Each locator has a name and they're numbered in the order of instantiation. The naming convention appears to be "__HK2_Generated_0" ... "__HK2_Generated_N".

In the following example we're saying that we want to override HK2's 0th locator with Guice. This is perfectly fine code if you have something like a Jetty Embedded application with one Connector.

public static void main(String[] args) {

  List<Module> modules = new ArrayList<>();
  
  modules.add(new JerseyGuiceModule("__HK2_Generated_0"));
  modules.add(new ServletModule());
  modules.add(new AbstractModule() {
    @Override
    protected void configure() {
      // ...
    }
  });
  
  Injector injector = Guice.createInjector(modules);
  JerseyGuiceUtils.install(injector);
  
  // ... continue ...
}

Complex Example

A more likely scenario is that you want to replace all "__HK2_Generated_*" instances. For something like a Dropwizard environment it'd replace the locator for the service connector as well as the admin connector.

public static void main(String[] args) {

  List<Module> modules = new ArrayList<>();
  
  modules.add(new ServletModule());
  modules.add(new AbstractModule() {
    @Override
    protected void configure() {
      // ...
    }
  });
  
  final Injector parentInjector = Guice.createInjector(modules);
  
  JerseyGuiceUtils.install(new ServiceLocatorGenerator() {
    @Override
    public ServiceLocator create(String name, ServiceLocator parent) {
      if (!name.startsWith("__HK2_Generated_")) {
        return null;
      }
      
      List<Module> modules = new ArrayList<>();
      
      modules.add(new JerseyGuiceModule(name));
      modules.add(new AbstractModule() {
        @Override
        protected void configure() {
          // ...
        }
      });
      
      return parentInjector.createChildInjector(modules)
          .getInstance(ServiceLocator.class);
    }
  });
  
  // ... continue ...
}

AOP with Guice

Please remember that Guice's AOP is only working with objects that were instantiated by Guice. The problem with HK2 is that it will instantiate an object on its own if it can.

You can force HK2 to use Guice by simply adding explicit bindings for these classes.

new AbstractModule() {
  @Override
  protected void configure() {
    bind(MyResource.class);
  }
};
Clone this wiki locally