Search code examples
javadependency-injectionguice

Inject Multiple Parameters Same interface in Java


I have to process multiple parsers(irrelevant). How can I inject correctly so StepProcessor could receive all classes? My class is:

@Inject
public StepProcessor(IParser... parsers) {
    if (parsers == null) {
        throw new IllegalArgumentException("Parsers cannot be null");
    }
    this.parsers = parsers;
}

@Override
public void process( String name ) {
    for (IParser parser : parsers) {
        System.out.println(parser.getName());
    }
}

How am I injecting?:

public class BasicModule extends AbstractModule {
@Override
protected void configure() {
    bind(IParser.class).to(XmlParser.class);
    bind(IParser.class).to(JsonParser.class);
    bind(IParser.class).to(TextParser.class);
    bind(IStepProcessor.class).to(StepProcessor.class);


}

}

I got: com.google.inject.CreationException: Unable to create injector, see the following errors:

1) A binding to IParser was already configured at BasicModule.configure(BasicModule.java:7). at BasicModule.configure(BasicModule.java:8)

MY usage:

Injector injector = Guice.createInjector(new BasicModule());
IStepProcessor comms = injector.getInstance(IStepProcessor.class);
comms.process("name");

Solution

  • You can use something called MultiBinding from Guice to achieve this.

    @Inject
    public StepProcessor(Set<IParser> parsers) { //Inject a set of IParser
        if (parsers == null) {
            throw new IllegalArgumentException("Parsers cannot be null");
        }
        this.parsers = parsers;
    }
    
    @Override
    public void process( String name ) {
        for (IParser parser : parsers) {
            System.out.println(parser.getName());
        }
    }
    

    Now change your module to this.

    public class BasicModule extends AbstractModule {
    
        @Override
        protected void configure() {
            MultiBinder<IParser> iParserBinder = MultiBinder.newSetBinder(binder(), IParser.class);
            iParserBinder.addBinding().to(XmlParser.class);
            iParserBinder.addBinding().to(JsonParser.class);
            iParserBinder.addBinding().to(TextParser.class);
            iParserBinder.addBinding().to(StepProcessor.class);
    }
    

    Don't forget the relevant imports. Do read the documentation before using it to understand how exactly it works. Hope this helps :)