Search code examples
javadependency-injectionjerseyvert.xhk2

Vertx + Jersey + HK2: ServiceLocator autobindings using @Contract and @Service


I'm trying to make use of vertx-jersey to create a webservice in which I can inject my own custom services as well as some more standard object such as the vertx instance itself.

At the moment I'm initialising the webserver like so (i.e. following this example):

Vertx vertx = Vertx.vertx();
vertx.runOnContext(aVoid -> {

    JsonObject jerseyConfiguration = new JsonObject();
    // ... populate the config with base path, resources, host, port, features, etc.

    vertx.getOrCreateContext().config().put("jersey", jerseyConfiguration);

    ServiceLocator locator = ServiceLocatorUtilities.bind(new HK2JerseyBinder());

    JerseyServer server = locator.getService(JerseyServer.class);
    server.start();
});

The issue I'm having is that I also want to be able to make use of dependency injection so I can automatically wire up my other services using the @Contract and @Service HK2 annotations.

The issue is that I'm already creating the ServiceLocator using the ServiceLocatorUtilities in which I explicitly bind HK2JerseyBinder and as I understand it I should only be creating a single ServiceLocator instance in which everything should be accessible/bound.

I'm also aware that I could call ServiceLocatorUtilities.createAndPopulateServiceLocator() instead, however it looks like the JerseyServer along with everything else bound in HK2JerseyBinder would then be missed out as they aren't annotated.

Is there a way that I can do both or work around this some how?


Solution

  • To expand on jwelll's comment:

    The ServiceLocatorUtilities is just what its name implies: it's just a utility to help create the ServiceLocator. To create it without the utilities you would use the ServiceLocatorFactory. This is what the utility does under the hood when you call one of its creation functions.

    ServiceLocator locator = ServiceLocatorFactory().getInstance().create(null);
    

    When you want to add services dynamically to locator, you can use the DynamicConfigurationService, which is a provided service by default.

    DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
    

    This service has a Populator that you can get and call it populate method for it to populate the locator with services from your inhabitant files (you can get these with the generator).

    Populator populator = dcs.getPopulator();
    populator.populate();
    

    This is all the ServiceLocatorUtilities.createAndPopulateServiceLocator() does.

    public static ServiceLocator createAndPopulateServiceLocator(String name) throws MultiException {
        ServiceLocator retVal = ServiceLocatorFactory.getInstance().create(name);
    
        DynamicConfigurationService dcs = retVal.getService(DynamicConfigurationService.class);
        Populator populator = dcs.getPopulator();
    
        try {
            populator.populate();
        }
        catch (IOException e) {
            throw new MultiException(e);
        }
    
        return retVal;
    }
    

    So since you already have an instance of the locator, all you need to do is get the dynamic configuration service, get the populator, and call its populate method.

    ServiceLocator locator = ServiceLocatorUtilities.bind(new HK2JerseyBinder());
    DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
    Populator populator = dcs.getPopulator();
    populator.populate();
    

    And if you wanted to do it the other way around (populator first), you could do

    ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
    ServiceLocatorUtilities.bind(locator, new HK2JerseyBinder()); 
    

    Under the hood, the utilities will just use the dynamic configuration service.

    There are a lot of different ways to (dynamically) add services. For more info, check out the docs. Another good source for information is the source code for the ServiceLocatorUtilities that I linked to.