1

I'm trying to understand how to best add something like Jest to Play.

In Play's 2.5.x dependency injection documentation, they show how to add singletons, which can be then be injected when needed via constructor injection.

While this makes perfect sense for classes I write, I don't really understand how to inject something like Jest, which is instantiated via a factory:

 JestClientFactory factory = new JestClientFactory();
 factory.setHttpClientConfig(new HttpClientConfig
                        .Builder("http://localhost:9200")
                        .multiThreaded(true)
            //Per default this implementation will create no more than 2 concurrent connections per given route
            .defaultMaxTotalConnectionPerRoute(<YOUR_DESIRED_LEVEL_OF_CONCURRENCY_PER_ROUTE>)
            // and no more 20 connections in total
            .maxTotalConnection(<YOUR_DESIRED_LEVEL_OF_CONCURRENCY_TOTAL>)
                        .build());
 JestClient client = factory.getObject();

In my controllers, how am I supposed to correctly inject Jest? Do I create a jest factory wrapper, and then in the constructor call getObject()? It doesn't seem like an ideal solution at all.

JestFactoryWrapper.java

@Singleton
class JestFactoryWrapper {

    private JestFactory jestFactory;

    JestFactoryWrapper() {
        this.jestFactory = ...
    }

    public JestFactory getObject() {
        return this.jestFactory.getObject()
    }
}

ApiController.java

@Inject
ApiController(JestFactoryWrapper jestFactory) {
    this.jestClient = factory.getObject();
}
user490895
  • 335
  • 2
  • 7
  • 17

1 Answers1

1

From documentation:

JestClient is designed to be singleton, don't construct it for each request!

https://github.com/searchbox-io/Jest/tree/master/jest

So injecting a factory is not a good choice.

I suppose it will be good to create a JestClient by the factory and bind class to the instance:

Example

Module:

public class Module extends AbstractModule {

  @Override
  protected void configure() {
    ...
    bind(JestClient.class).toInstance(jestFactory.getObject());
    ...
  }
}

Usage:

@Inject
ApiController(JestClient jestClient) {
    this.jestClient = jestClient;
}

Provider Bindings

Create a provider singleton.

@Singleton
public class JestClientProvider implements Provider<JestClient> {

    private final JestClient client;

    @Inject
    public JestClientProvider(final Configuration configuration, final ApplicationLifecycle lifecycle) {
        // Read the configuration.
        // Do things on the start of the application.

        ...

        client = jestFactory.getObject();

        lifecycle.addStopHook(() -> {
            // Do things on the stop of the application.
            // Close the connections and so on. 
        })
    }

    @Override
    public JestClient get() {
        return client;
    }
}

Bind it in the the module:

bind(JestClient.class).toProvider(JestClientProvider.class).asEagerSingleton();

Use it:

@Inject
ApiController(JestClient jestClient) {
    this.jestClient = jestClient;
}
Andriy Kuba
  • 8,093
  • 2
  • 29
  • 46
  • Thanks, this helps. As a follow up, should the factory be initialized in Module.java, or can itself also be injected? I've been looking for guice best practices but couldn't really find anything related to this specifically. – user490895 May 04 '17 at 16:52
  • See the updated "Provider Bindings" section in my answer – Andriy Kuba May 05 '17 at 07:19