Search code examples
javaguice

Binding same parameter to multiple implementations with Guice's MultiBinder and Asisstedinjection


I have a set of validator classes that all extend a common abstract class, all with the same constructor

public abstract class AbstractValidator {
    public AbstractValidator(DataSource dataSource) {
        // ...
    }
}

public class Validator1 extends AbstractValidator {
    public Validator1(DataSource dataSource) {
        super(dataSource);
    }
}

public class Validator2 extends AbstractValidator {
    public Validator2(DataSource dataSource) {
        super(dataSource);
    }
}

I want the ability for Guice to

  1. Know how to construct all of these validators, injecting the same DataSource into all of them
  2. Inject all of the validators into a class using a MultiBinder

Through some googling, it looked like I could use AssistedInject, but the problem is that if I wanted to do that, I would have to make a factory for every validator, which is a huge amount of boilerplate. Because they all have the same constructor, I feel like there must be a better way. My DataSource object is created outside of Guice, and I just want to bind it to all instances of DataSource.class in my configure.

One thing I'm willing to change is to have some kind of factory method that would allow me to create a validator from just a DataSource... I recognize my desire to use constructors might not be type safe.

This answer looks almost like what I want, but it's in Scala, which I'm not familiar enough with to fully understand.


Solution

  • There is no need for AssistedInject.

    You can bind you instance of DataSource like this:

    DataSource dataSource = ...;
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Provides @Singleton DataSource provideDataSource() { return dataSource; }
      @ProvidesIntoSet Validator provideValidator1(DataSource dataSource) { return new Validator1(dataSource); }
      @ProvidesIntoSet Validator provideValidator2(DataSource dataSource) { return new Validator2(dataSource); }
    });
    
    Set<Validator> validators = injector.get(new Key<Set<Validator>>(){});