Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make requestInjection with an explicit type actually use the type #1071

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/src/com/google/inject/AbstractModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ protected void addError(Message message) {
binder().addError(message);
}

/**
* @see Binder#requestInjection(TypeLiteral, Object)
* @since 4.1
*/
protected <T> void requestInjection(TypeLiteral<T> type, T instance) {
binder().requestInjection(type, instance);
}

/**
* @see Binder#requestInjection(Object)
* @since 2.0
Expand Down
4 changes: 2 additions & 2 deletions core/src/com/google/inject/internal/BindingProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public Boolean visit(InstanceBinding<? extends T> binding) {
// the processor was constructed w/ it
Initializable<T> ref =
initializer.requestInjection(
injector, instance, (Binding<T>) binding, source, injectionPoints);
injector, null, instance, (Binding<T>) binding, source, injectionPoints);
ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
InternalFactory<? extends T> scopedFactory =
Scoping.scope(key, injector, factory, source, scoping);
Expand All @@ -124,7 +124,7 @@ public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
Initializable<? extends javax.inject.Provider<? extends T>> initializable =
initializer.<javax.inject.Provider<? extends T>>requestInjection(
injector, provider, null, source, injectionPoints);
injector, null, provider, null, source, injectionPoints);
// always visited with Binding<T>
@SuppressWarnings("unchecked")
InternalFactory<T> factory =
Expand Down
4 changes: 4 additions & 0 deletions core/src/com/google/inject/internal/Errors.java
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,10 @@ public Errors staticInjectionOnInterface(Class<?> clazz) {
return addMessage("%s is an interface, but interfaces have no static injection points.", clazz);
}

public Errors requestInjectionWithDifferentTypes(TypeLiteral<?> type1, TypeLiteral<?> type2) {
return addMessage("Requested injection for the same object with different types: %s and %s", type1, type2);
}

public Errors cannotInjectFinalField(Field field) {
return addMessage("Injected field %s cannot be final.", field);
}
Expand Down
23 changes: 18 additions & 5 deletions core/src/com/google/inject/internal/Initializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ final class Initializer {
*/
<T> Initializable<T> requestInjection(
InjectorImpl injector,
TypeLiteral<T> type,
T instance,
Binding<T> binding,
Object source,
Expand All @@ -93,15 +94,26 @@ <T> Initializable<T> requestInjection(
return Initializables.of(instance);
}

if (type == null) {
@SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T>
TypeLiteral<T> instanceType = TypeLiteral.get((Class<T>) instance.getClass());
type = instanceType;
}

if (initializablesCache.containsKey(instance)) {
@SuppressWarnings("unchecked") // Map from T to InjectableReference<T>
Initializable<T> cached = (Initializable<T>) initializablesCache.get(instance);
InjectableReference<T> cached = (InjectableReference<T>) initializablesCache.get(instance);
if (!cached.type.equals(type)) {
new Errors(source).requestInjectionWithDifferentTypes(cached.type, type)
.throwConfigurationExceptionIfErrorsExist();
}
return cached;
}

InjectableReference<T> injectableReference =
new InjectableReference<T>(
injector,
type,
instance,
binding == null ? null : binding.getKey(),
provisionCallback,
Expand Down Expand Up @@ -157,6 +169,7 @@ private static class InjectableReference<T> implements Initializable<T> {
private volatile MembersInjectorImpl<T> membersInjector = null;

private final InjectorImpl injector;
private final TypeLiteral<T> type;
private final T instance;
private final Object source;
private final Key<T> key;
Expand All @@ -165,6 +178,7 @@ private static class InjectableReference<T> implements Initializable<T> {

public InjectableReference(
InjectorImpl injector,
TypeLiteral<T> type,
T instance,
Key<T> key,
ProvisionListenerStackCallback<T> provisionCallback,
Expand All @@ -173,19 +187,18 @@ public InjectableReference(
this.injector = injector;
this.key = key; // possibly null!
this.provisionCallback = provisionCallback; // possibly null!
this.type = checkNotNull(type, "type");
this.instance = checkNotNull(instance, "instance");
this.source = checkNotNull(source, "source");
this.lock = checkNotNull(lock, "lock");
}

public void validate(Errors errors) throws ErrorsException {
@SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T>
TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
membersInjector = injector.membersInjectorStore.get(type, errors.withSource(source));
Preconditions.checkNotNull(
membersInjector,
"No membersInjector available for instance: %s, from key: %s",
instance,
"No membersInjector available for type: %s, from key: %s",
type,
key);
state = InjectableReferenceState.VALIDATED;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ public Boolean visit(InjectionRequest<?> request) {
injectionPoints = e.getPartialValue();
}

initializer.requestInjection(
injector, request.getInstance(), null, request.getSource(), injectionPoints);
requestInjection(request, injectionPoints);
return true;
}

private <T> void requestInjection(InjectionRequest<T> request, Set<InjectionPoint> injectionPoints) {
initializer.requestInjection(
injector, request.getType(), request.getInstance(), null, request.getSource(), injectionPoints);
}

void validate() {
for (StaticInjection staticInjection : staticInjections) {
staticInjection.validate();
Expand Down
2 changes: 1 addition & 1 deletion core/src/com/google/inject/spi/InjectionRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public TypeLiteral<T> getType() {
* the valid injection points.
*/
public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
return InjectionPoint.forInstanceMethodsAndFields(instance.getClass());
return InjectionPoint.forInstanceMethodsAndFields(type);
}

@Override
Expand Down
43 changes: 43 additions & 0 deletions core/test/com/google/inject/RequestInjectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,47 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {}
}
});
}

class NeedsThing<T> {
@Inject T thing;
}

public void testRequestInjectionWithParameterizedType() {
final NeedsThing<String> thing = new NeedsThing<String>();

Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
bind(String.class).toInstance("hi");
requestInjection(new TypeLiteral<NeedsThing<String>>(){}, thing);
}
});

assertEquals("hi", thing.thing);
}

public void testMultipleInjectionRequestsWithDifferentTypes() {
final NeedsThing<String> thing = new NeedsThing<String>();
final TypeLiteral<NeedsThing<String>> type1 = new TypeLiteral<NeedsThing<String>>(){};
final TypeLiteral<NeedsThing<Integer>> type2 = new TypeLiteral<NeedsThing<Integer>>(){};

class MixTypes extends AbstractModule {
@Override
protected void configure() {
requestInjection(type1, thing);
requestInjection(type2, (NeedsThing) thing);
}
}

try {
Guice.createInjector(new MixTypes());
fail();
} catch (ConfigurationException expected) {
assertContains(
expected.getMessage(),
"1) Requested injection for the same object with different types: " + type1 + " and " + type2,
"at " + MixTypes.class.getName() + ".configure(");
}
}
}