Derek Gourlay
Derek Gourlay

Reputation: 279

Google Guice - How to pass a parameter to a third party library Factory class

I am attempting to migrate from Spring to Guice for dependency injection. Here is a sample snippet from a Spring xml config:

<bean id="connectionFactory" class="org.somethirdparty.MyConnectionFactory">
  <property name="connectionUrl" value="${urls.connectionUrl}"/>
  <property name="ackMode" value="unordered"/>
  <property name="timeout" ref="timeoutBean"/>
</bean>

<bean id="timeoutBean" class="java.lang.Integer">
  <constructor-arg value="10000"/>
</bean>

I am struggling with figuring out how to parameterize MyConnectionFactory with Google Guice. I cannot annotate the constructor or methods of 'MyConnectionFactory' as this is a class provided by a 3rd party library.

After reading the Guice FAQ it seems to me the only option is to make a Factory for the Factory? That seems silly to me!

Upvotes: 2

Views: 2505

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95654

You might need to make a Factory for the MyConnectionFactory, but only if you actually need to vary the parameters passed to MyConnectionFactory at runtime. Otherwise, you can get away with making a Provider—which is a Factory after all, I guess—or its slimmer cousin the @Provides Method. (I'm guessing the class in question takes unspecific or primitive arguments, or else a toConstructor binding is yet another possibility.)

The Factory would look like this:

public class MyConnectionFactoryFactory {
  @Inject Provider<SomeDependency> someDependencyProvider;

  public MyConnectionFactory create(String url) {
    return new MyConnectionFactory(someDependencyProvider.get(), url, 10000);
  }
}

The Provider would look identical, except it'd implement Provider<MyConnectionFactory> and create would instead be a zero-arg get(). You can bind that through bind(MyConnectionFactory.class).toProvider(MyConnectionFactoryProvider.class).

However, if you know all your constructor parameters at configuration time, you could equally create a @Provides method in your Module, which would look like this:

public class MyModule extends AbstractModule {
  @Override public void configure() { /* your configuration here */ }

  /* FYI: a @Provides method by any other name would return as sweet */
  @Provides MyConnectionFactory getConnectionFactory(SomeDependency dependency) {
    return new MyConnectionFactory(dependency, url, 10000);
  }
}

...which takes your "wrapper code" boilerplate to three extra non-blank lines. Remember, Guice will automatically bind any combination of X, Provider<X>, or @Provides X to any injection of X or Provider<X> automatically for you, so feel free to bind it however is most convenient.

Upvotes: 2

Related Questions