Skip to content

Commit

Permalink
Fix injection when using generics
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexDochioiu committed Mar 26, 2021
1 parent 6ab4ade commit d497e93
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example;

import dagger.BindsInstance;
import dagger.Component;
import javax.inject.Inject;

@Component
public interface MemberInjectionGenericInjector
extends Injector<MemberInjectionGenericInjector.Target> {

@Component.Factory
interface Factory {
MemberInjectionGenericInjector create(@BindsInstance String one);
}

class Target {
@Inject String one;
}
}

interface Injector<T> {
void inject(T target);
}
10 changes: 10 additions & 0 deletions integration-tests/src/test/java/com/example/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,16 @@ public void memberInjectionEmptyClass() {
// No state, nothing to verify, except it didn't throw.
}

@Test
public void memberInjectionGenericInjector() {
final String expectedStr = "expected";
MemberInjectionGenericInjector component =
backend.factory(MemberInjectionGenericInjector.Factory.class).create(expectedStr);
MemberInjectionGenericInjector.Target target = new MemberInjectionGenericInjector.Target();
component.inject(target);
assertThat(target.one).isEqualTo(expectedStr);
}

@Test
public void memberInjectionEmptyAbstractClass() {
MemberInjectionEmptyAbstract component = backend.create(MemberInjectionEmptyAbstract.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -60,8 +61,24 @@ private ComponentInvocationHandler(Scope scope) {
}

MethodInvocationHandler handler = handlers.get(method);
final Class<?>[] parameterTypes = method.getParameterTypes();
if (handler == null) {
handler = createMethodInvocationHandler(method, scope);
final int argsCount = args != null ? args.length : 0;
for (int index = 0; index < argsCount; ++index) {
final Object arg = args[index];
if (arg == null) continue; // ignore null arguments
if (!TypeVariable.class.isAssignableFrom(
method.getGenericParameterTypes()[index].getClass()))
continue; // ignore args not using generics

final Class<?> parameter = parameterTypes[index];
// Replace generic boundary class with actual class being invoked
if (parameter.isAssignableFrom(arg.getClass())) {
parameterTypes[index] = arg.getClass();
}
}

handler = createMethodInvocationHandler(method, parameterTypes, scope);
MethodInvocationHandler replaced = handlers.putIfAbsent(method, handler);
if (replaced != null) {
handler = replaced;
Expand All @@ -71,9 +88,8 @@ private ComponentInvocationHandler(Scope scope) {
}

private static ComponentInvocationHandler.MethodInvocationHandler createMethodInvocationHandler(
Method method, Scope scope) {
Method method, Class<?>[] parameterTypes, Scope scope) {
Type returnType = method.getGenericReturnType();
Class<?>[] parameterTypes = method.getParameterTypes();

if (returnType instanceof Class<?>) {
Class<?> returnClass = (Class<?>) returnType;
Expand Down

0 comments on commit d497e93

Please sign in to comment.