Search code examples
javahk2

How do I make a HK2 ServiceLocator use the Singleton service instances from the ServiceLocator that it's bridged from?


We are using using ExtrasUtilities.bridgeServiceLocator() to inject existing Singleton application services created in one ServiceLocator into Jersey RESTful Web Services by bridging the app ServiceLocator into the Jersey ServiceLocator.

However the Singletons that exist in the 'outer' locator aren't being used - each of the services is being created once again when injected into the Jersey services. It seems the Singleton is only visible within the scope of a ServiceLocator, even if it's bridged.

Is this the intended behaviour? And if so is there any way to change this behaviour and have a true Singleton across bridged ServiceLocators?

I have extracted the issue out into a set of test classes that illustrate the point below:

public class BridgedServiceTest
{
  private ServiceLocator _outerServiceLocator;
  private ServiceLocator _innerServiceLocator;

  @Test
  public void testBridgedInnerServiceOK() throws Exception
  {
    ServiceLocatorFactory serviceLocatorFactory = ServiceLocatorFactory.getInstance();

    _outerServiceLocator = serviceLocatorFactory.create("Outer");
    ServiceLocatorUtilities.addClasses(_outerServiceLocator, SingletonServiceImpl.class);

    _innerServiceLocator = serviceLocatorFactory.create("Inner");
    ExtrasUtilities.bridgeServiceLocator(_innerServiceLocator, _outerServiceLocator);

    final Client client1 = new Client();
    _outerServiceLocator.inject(client1);
    assertThat(SingletonServiceImpl.instanceCount.get(), Matchers.is(1));
    client1.test();

    final Client client2 = new Client();
    _innerServiceLocator.inject(client2);
    // next line fails as instance count is 2
    assertThat(SingletonServiceImpl.instanceCount.get(), Matchers.is(1));
    client2.test();
  }

  @After
  public void tearDown() throws Exception
  {
    _innerServiceLocator.shutdown();
    _outerServiceLocator.shutdown();
  }
}

@Contract
public interface SingletonService
{
  void fulfil();
}

@Service
public class SingletonServiceImpl implements SingletonService
{
  public static AtomicInteger instanceCount = new AtomicInteger();

  @PostConstruct
  public void postConstruct()
  {
    instanceCount.incrementAndGet();
  }

  @Override
  public void fulfil()
  {
    System.out.println("Contract Fulfilled.");
  }
}

public class Client
{
  @Inject
  private SingletonService _singletonService;

  public void test()
  {
    _singletonService.fulfil();
  }

  public SingletonService getSingletonService()
  {
    return _singletonService;
  }
}

Solution

  • There was a bug in the ServiceLocator bridge which has been fixed. The fix will be in hk2 2.5.0-b07 or later!