Last active
December 14, 2015 15:08
-
-
Save electrotype/5105100 to your computer and use it in GitHub Desktop.
Bug Guice - ConstructorInjector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.junit.Assert.*; | |
import java.util.UUID; | |
import org.junit.Test; | |
import com.google.inject.AbstractModule; | |
import com.google.inject.Guice; | |
import com.google.inject.Inject; | |
import com.google.inject.Injector; | |
import com.google.inject.TypeLiteral; | |
import com.google.inject.assistedinject.Assisted; | |
import com.google.inject.assistedinject.FactoryModuleBuilder; | |
import com.google.inject.matcher.AbstractMatcher; | |
import com.google.inject.spi.InjectionListener; | |
import com.google.inject.spi.TypeEncounter; | |
import com.google.inject.spi.TypeListener; | |
public class ExampleTest | |
{ | |
public static class ClassAAA | |
{ | |
private final String id; | |
private final boolean myParam; | |
private final IClassBBBFactory classBBBFactory; | |
private ClassBBB clasBBB; | |
@Inject | |
public ClassAAA(@Assisted boolean myParam, | |
IClassBBBFactory classBBBFactory) | |
{ | |
this.myParam = myParam; | |
this.id = UUID.randomUUID().toString(); | |
this.classBBBFactory = classBBBFactory; | |
} | |
public void init() | |
{ | |
if(this.myParam) | |
{ | |
this.clasBBB = this.classBBBFactory.create(UUID.randomUUID().toString()); | |
} | |
} | |
public String getId() | |
{ | |
return this.id; | |
} | |
public ClassBBB getClassBBB() | |
{ | |
return this.clasBBB; | |
} | |
} | |
public static class ClassBBB | |
{ | |
private final IClassAAAFactory classAAAFactory; | |
private ClassAAA clasAAACreatedByClassBBB; | |
@Inject | |
public ClassBBB(@Assisted String myParam, | |
IClassAAAFactory classAAAFactory) | |
{ | |
this.classAAAFactory = classAAAFactory; | |
} | |
public void init() | |
{ | |
// The problem is here. Even if the factory should return a new instance | |
// of ClassAAA, it returns the one that is creating ClassBBB! | |
this.clasAAACreatedByClassBBB = this.classAAAFactory.create(false); | |
} | |
public ClassAAA getClasAAACreatedByClassBBB() | |
{ | |
return this.clasAAACreatedByClassBBB; | |
} | |
} | |
public static interface IClassAAAFactory | |
{ | |
public ClassAAA create(boolean someParam); | |
} | |
public static interface IClassBBBFactory | |
{ | |
public ClassBBB create(String someParam); | |
} | |
@Test | |
public void bugGuiceConstructorInjector() | |
{ | |
Injector injector = Guice.createInjector(new AbstractModule() | |
{ | |
@Override | |
protected void configure() | |
{ | |
bindListener(new AbstractMatcher<TypeLiteral<?>>() | |
{ | |
@Override | |
public boolean matches(TypeLiteral<?> typeLiteral) | |
{ | |
return ClassAAA.class.isAssignableFrom(typeLiteral.getRawType()) || | |
ClassBBB.class.isAssignableFrom(typeLiteral.getRawType()); | |
} | |
}, | |
new TypeListener() | |
{ | |
@Override | |
public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) | |
{ | |
typeEncounter.register(new InjectionListener<I>() | |
{ | |
@Override | |
public void afterInjection(Object obj) | |
{ | |
if(obj instanceof ClassAAA) | |
{ | |
((ClassAAA)obj).init(); | |
} | |
if(obj instanceof ClassBBB) | |
{ | |
((ClassBBB)obj).init(); | |
} | |
} | |
}); | |
} | |
}); | |
install(new FactoryModuleBuilder().build(IClassAAAFactory.class)); | |
install(new FactoryModuleBuilder().build(IClassBBBFactory.class)); | |
} | |
}); | |
IClassAAAFactory classAAAFactory = injector.getInstance(IClassAAAFactory.class); | |
ClassAAA classAAA = classAAAFactory.create(true); | |
// Shouldn't be the same id! | |
assertNotEquals(classAAA.getClassBBB().getClasAAACreatedByClassBBB().getId(), classAAA.getId()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that I check the IDs and not the references, in case there are proxies involved.