How to get HK2 ServiceLocator in Jersey 2.12?

jsr___ picture jsr___ · Sep 8, 2014 · Viewed 8.4k times · Source

I would like to create a singleton instance of a class that is not involved in Jersey as a Resource or Service and yet would like its dependencies injected from the Jersey ServiceLocator.

I can register this class manually in my ResourceConfig constructor, the ResourceConfig is then passed in to the Grizzly factory method like so:

ResourceConfig resourceConfig = new DeviceServiceApplication();

LOGGER.info("Starting grizzly2...");
return GrizzlyHttpServerFactory.createHttpServer(BASE_URI,
                                                 resourceConfig, mServiceLocator);

The problem that remains is how to get a reference to the Jersey ServiceLocator so I can call createAndInitialize() to get my object with dependencies injected. I see in previous Jersey versions there were constructor variants that expect an ApplicationHandler, which of course provides access to the service locator (how I initialise that is another matter). You can also see I have tried passing in a parent ServiceLocator but of course the resolution happens from child -> parent locator and not in the other direction so asking the parent for my object fails because the Jersey @Contract and @Service types aren't visible here.

Do I need to use something other than GrizzlyHttpServerFactory ? Do I give up and manually wire my singleton's dependencies?

Answer

endeavor picture endeavor · Oct 19, 2014

I was able to get a reference to ServiceLocator by registering a ContainerLifecycleListener.

In the onStartup(Container container) method, call container.getApplicationHandler().getServiceLocator().

This example stores the reference as a member variable of ResourceConfig which you can use elsewhere via an accessor.

class MyResourceConfig extends ResourceConfig
{
    // won't be initialized until onStartup()
    ServiceLocator serviceLocator;

    public MyResourceConfig()
    {
        register(new ContainerLifecycleListener()
        {
            public void onStartup(Container container)
            {
                // access the ServiceLocator here
                serviceLocator = container.getApplicationHandler().getServiceLocator();

                // ... do what you need with ServiceLocator ...
                MyService service = serviceLocator.createAndInitialize(MyService.class);
            }

            public void onReload(Container container) {/*...*/}
            public void onShutdown(Container container) {/*...*/}
        });
    }

    public ServiceLocator getServiceLocator()
    {
        return serviceLocator;
    }
}

then elsewhere:

MyService service
    = myResourceConfig.getServiceLocator().createAndInitialize(MyService.class);