Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get HK2 ServiceLocator in a Jersey2 ServletContainer?

I'd like to get Jersey2 and Guice to cooperate together, which is apparently rather difficult. I've seen some solution to this involving using the HK2-to-Guice bridge. But the bridge rely on getting the HK2 ServiceLocator instance in the init() of a custom Jersey2 ServletContainer in order to initialize GuiceBrige:

public class MyServletContainer extends ServletContainer {
  @Override public void init() {
    ServiceLocator sloc = getApplicationHandler().getServiceLocator();
    ...
} }

But somehow in the latests version of Jersey (2.26), the getServiceLocator() does not longer exists in ApplicationHandler. How can I get it in this context?

like image 855
Laurent Grégoire Avatar asked Oct 19 '17 07:10

Laurent Grégoire


1 Answers

Disclaimer: I don't use Guice, so this is not something that I have tested. So I don't know if what the OP is trying to do will even work. I am simply answering the main question of how to get the ServiceLocator.


As mentioned in my comment here, starting 2.26, Jersey no longer has a hard dependency on HK2. So throughout its codebase, you will no longer see a reference to a ServiceLocator, but instead, a higher level InjectionManager. The InjectionManager has the same purpose as the ServiceLocator, but the abstraction allows for different implementations of the dependency injection provider. This is why, when using 2.26, we need to add the jersey-hk2 dependency. This is the HK2 implementation of the InjectionManager. In this implementation, the InjectionManager will simply delegate calls to the underlying ServiceLocator where appropriate.

That being said, the ApplicationHandler gives you access to the InjectionManager now, rather than the ServiceLocator. The ServiceLocator itself is a service, so if you have a locator you could do the following (which is pointless, but it just shows my point)

ServiceLocator locator = getServiceLocator();
locator = locator.getService(ServiceLocator.class);

This means that you can also get the locator from the InjectionManager, which is just a high level delegator for the underlying locator

InjectionManager im = getApplicationHandler().getInjectionManager();
ServiceLocator locator = im.getInstance(ServiceLocator.class);

One thing that needs to be pointed out, and the main reason for my disclaimer is that you need to call super.init() first in your init() method, or else you will get an NPE when you try to get the ApplicationHandler. The problem with this is that there is alot of initialization done; pretty much the entire application is initialized. So it may or may not be too late to try and add your Guice integration.

Here are some other places where I have seen this integration done. And I believe they would all be hit before you trying to do it at the end of the init().

  • In a ResourceConfig constructor, where you could inject the InjectionManager.
  • In a Feature where you could get the InjectionManager through the InjectionManagerProvider static method.
  • I have not seen any implementation of this, but I think the preferred location to do the bridge would be in a ComponentProvider, as mentioned in the docs. The only implementation I have seen is for Spring. You can see the source in the jersey-spring4. This is probably requires more work, but I think it would be the most appropriate location, as it is called before all the other previous options. It may not be required though, as I've seen others get away with the other two options.
like image 186
Paul Samsotha Avatar answered Nov 02 '22 23:11

Paul Samsotha