Search code examples
javagenericsguiceassisted-inject

How to make Multibinder work with FactoryModuleBuilder and Generics using Guice?


I've read Google guice - multibinding + generics + assistedinject but it doesn't seem to answer my specific scenario. Here's what i have:

The interfaces to use with FactoryModuleBuilder

public interface IFilterFactory<T extends IFilter> {
    T create(FilterConfig config);
}
public interface IFilterOneFactory extends IFilterFactory<FilterOne> {}
public interface IFilterTwoFactory extends IFilterFactory<FilterTwo> {}

My Guice module:

@Override
protected void configure() {
    install(new FactoryModuleBuilder().build(IFilterOneFactory.class));
    install(new FactoryModuleBuilder().build(IFilterTwoFactory.class));

    Multibinder<IFilterFactory<?>> filterBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<IFilterFactory<?>>() {});
    filterBinder.addBinding().to(IFilterOneFactory.class);
    filterBinder.addBinding().to(IFilterTwoFactory.class);
}

My main filter that is supposed to combine all other filters:

public class MainFilterFactory {
    @Inject
    MainFilterFactory(Set<IFilterFactory<?>> factories) {
        this.factories = factories;
    }

    public MainFilter get(String groupKey) {
        FilterConfig fc = new FilterConfig(groupKey);
        IFilter[] filters = this.factories.stream().map(f -> f.create(fc)).toArray(IFilter[]::new);
        return new MainFilter(Arrays.asList(filters));
    }
}

That actually doesn't work. And i get the following stacktraces:

[WARNING]
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
        at java.lang.Thread.run(Thread.java:745)
[WARNING]
com.google.inject.internal.util.$ComputationException: java.lang.ArrayIndexOutOfBoundsException: 19640
        at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:553)
        at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:419)
        at com.google.inject.internal.util.$CustomConcurrentHashMap$ComputingImpl.get(CustomConcurrentHashMap.java:2041)
        at com.google.inject.internal.util.$StackTraceElements.forType(StackTraceElements.java:70)
        at com.google.inject.internal.Errors.formatSource(Errors.java:687)
        at com.google.inject.internal.Errors.format(Errors.java:555)
        at com.google.inject.CreationException.getMessage(CreationException.java:48)
        at java.lang.Throwable.getLocalizedMessage(Throwable.java:391)
        at java.lang.Throwable.toString(Throwable.java:480)
        at java.lang.String.valueOf(String.java:2982)
        at java.lang.StringBuilder.append(StringBuilder.java:131)
        at java.lang.Throwable.printEnclosedStackTrace(Throwable.java:695)
        at java.lang.Throwable.printStackTrace(Throwable.java:667)
        at java.lang.Throwable.printStackTrace(Throwable.java:643)
        at org.apache.maven.cli.PrintStreamLogger.warn(PrintStreamLogger.java:131)
        at org.apache.maven.monitor.logging.DefaultLog.warn(DefaultLog.java:93)
        at org.codehaus.mojo.exec.ExecJavaMojo$IsolatedThreadGroup.uncaughtException(ExecJavaMojo.java:386)
        at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:309)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 19640
        at com.google.inject.internal.asm.$ClassReader.<init>(Unknown Source)
        at com.google.inject.internal.asm.$ClassReader.<init>(Unknown Source)
        at com.google.inject.internal.asm.$ClassReader.<init>(Unknown Source)
        at com.google.inject.internal.util.$LineNumbers.<init>(LineNumbers.java:62)
        at com.google.inject.internal.util.$StackTraceElements$1.apply(StackTraceElements.java:36)
        at com.google.inject.internal.util.$StackTraceElements$1.apply(StackTraceElements.java:33)
        at com.google.inject.internal.util.$MapMaker$StrategyImpl.compute(MapMaker.java:549)
        ... 18 more

Am I doing anything wrong here ?


Solution

  • This is actually a Guice compatibility issue between Guice 3.0 and Java 8. See: https://github.com/google/guice/issues/757

    I was missing some @Assisted and @Inject in the constructors and Guice failed to report the error because some lambdas were used in those classes.

    Commenting the lambdas allowed me to see the errors and fix them. I then Uncommented them and everything seems to work as intended.