From 0b2210e8a159975b62b92f794e3898833563aba6 Mon Sep 17 00:00:00 2001 From: Laimonas Turauskas Date: Thu, 18 Jul 2019 15:00:24 -0700 Subject: [PATCH] Adding module generic support. --- integration-tests/upstream/build.gradle | 18 +++---- .../reflect/ReflectiveModuleParser.java | 50 ++++++++++++++++++- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/integration-tests/upstream/build.gradle b/integration-tests/upstream/build.gradle index bb7b80bd..cdc7e8ef 100644 --- a/integration-tests/upstream/build.gradle +++ b/integration-tests/upstream/build.gradle @@ -43,15 +43,15 @@ test.filter { excludeTest 'dagger.functional.BasicTest', null // TODO reflect bug! Generics don't work well. - excludeTest 'dagger.functional.GenericTest', 'complexGenerics' - excludeTest 'dagger.functional.GenericTest', 'genericModules' - excludeTest 'dagger.functional.GenericTest', 'membersInjections' - excludeTest 'dagger.functional.GenericTest', 'noDepsGenerics' - excludeTest 'dagger.functional.GenericTest', 'packagePrivateTypeParameterDependencies' - excludeTest 'dagger.functional.GenericTest', 'publicSubclassWithPackagePrivateTypeParameterOfSuperclass' - excludeTest 'dagger.functional.GenericTest', 'testGenericComponentCreate' - excludeTest 'dagger.functional.GenericTest', 'testGenericDoubleReferences' - excludeTest 'dagger.functional.GenericTest', 'testGenericSimpleReferences' +// excludeTest 'dagger.functional.GenericTest', 'complexGenerics' +// excludeTest 'dagger.functional.GenericTest', 'genericModules' +// excludeTest 'dagger.functional.GenericTest', 'membersInjections' +// excludeTest 'dagger.functional.GenericTest', 'noDepsGenerics' +// excludeTest 'dagger.functional.GenericTest', 'packagePrivateTypeParameterDependencies' +// excludeTest 'dagger.functional.GenericTest', 'publicSubclassWithPackagePrivateTypeParameterOfSuperclass' +// excludeTest 'dagger.functional.GenericTest', 'testGenericComponentCreate' +// excludeTest 'dagger.functional.GenericTest', 'testGenericDoubleReferences' +// excludeTest 'dagger.functional.GenericTest', 'testGenericSimpleReferences' excludeTest 'dagger.functional.binds.BindsTest', 'bindDelegates' excludeTest 'dagger.functional.binds.BindsTest', 'bindWithScope' diff --git a/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java b/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java index a7fa7d2b..1ec29c54 100644 --- a/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java +++ b/reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java @@ -22,7 +22,10 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -30,9 +33,11 @@ final class ReflectiveModuleParser { static void parse(Class moduleClass, @Nullable Object instance, Scope.Builder scopeBuilder) { - for (Class target : Reflection.getDistinctTypeHierarchy(moduleClass)) { + Set> hierarchy = Reflection.getDistinctTypeHierarchy(moduleClass); + for (Class target : hierarchy) { for (Method method : target.getDeclaredMethods()) { Type returnType = method.getGenericReturnType(); + Annotation[] annotations = method.getAnnotations(); Annotation qualifier = findQualifier(annotations); @@ -85,7 +90,8 @@ static void parse(Class moduleClass, @Nullable Object instance, Scope.Builder if (method.getAnnotation(Provides.class) != null) { ensureNotPrivate(method); - Key key = Key.of(qualifier, returnType); + + Key key = Key.of(qualifier, resolveType(hierarchy, target, returnType)); Binding binding = new UnlinkedProvidesBinding(instance, method); addBinding(scopeBuilder, key, binding, annotations); } @@ -94,6 +100,46 @@ static void parse(Class moduleClass, @Nullable Object instance, Scope.Builder } } + private static Type resolveType(Set> moduleClass, Class target, Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + + Type[] typeArguments = new Type[parameterizedType.getActualTypeArguments().length]; + + int index = 0; + for (Type typeArgument : parameterizedType.getActualTypeArguments()) { + if (typeArgument instanceof TypeVariable) { + for (Class possibility : moduleClass) { + if (target != possibility && target.isAssignableFrom(possibility)) { + ParameterizedType genericSuperclass = ((ParameterizedType) possibility.getGenericSuperclass()); + if (genericSuperclass.getRawType() == target) { + int typeIndex = 0; + TypeVariable>[] typeParameters = target.getTypeParameters(); + for (int i = 0; i < typeParameters.length; i++) { + if (typeArgument == typeParameters[i]) { + typeIndex = i; + } + } + + typeArguments[index] = genericSuperclass.getActualTypeArguments()[typeIndex]; + + } + } + } + } else { + typeArguments[index] = typeArgument; + } + + + index += 1; + } + + return new ParameterizedTypeImpl(parameterizedType.getOwnerType(), parameterizedType.getRawType(), typeArguments); + } + + return type; + } + private static void addBinding( Scope.Builder scopeBuilder, Key key, Binding binding, Annotation[] annotations) { Annotation scope = findScope(annotations);