diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java index 92f6a29f8..cc4119270 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java @@ -563,8 +563,14 @@ void addDependsOnGeneric(Set set) { } void builderGetDependency(Append writer, String builderName) { - writer.append(builderName).append(".").append(utilType.getMethod(nullable, isBeanMap)); - if (!genericType.isGeneric() || genericType.param0().kind() == TypeKind.WILDCARD) { + final boolean wildcard = isWildcard(); + final var wildParam = wildcard ? String.format("<%s>", genericType.shortWithoutAnnotations()) : ""; + writer + .append(builderName) + .append(".") + .append(wildParam) + .append(utilType.getMethod(nullable, isBeanMap)); + if (!genericType.isGeneric() || wildcard) { writer.append(Util.shortName(genericType.mainType())).append(".class"); } else { writer.append("TYPE_").append(Util.shortName(genericType).replace(".", "_")); @@ -585,6 +591,11 @@ void builderGetDependency(Append writer, String builderName) { writer.append(")"); } + private boolean isWildcard() { + return genericType.isGeneric() + && genericType.componentTypes().stream().allMatch(g -> g.kind() == TypeKind.WILDCARD); + } + String simpleName() { return simpleName; } @@ -602,7 +613,7 @@ boolean isGenericParam() { } Dependency dependsOn() { - return new Dependency(paramType, named, utilType.isCollection()); + return new Dependency(isWildcard() ? genericType.mainType() : paramType, named, utilType.isCollection()); } void addImports(ImportTypeMap importTypes) { diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java index b7e9df67e..dbaf5b15b 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java @@ -210,13 +210,17 @@ private void addSuperType(TypeElement element, TypeMirror mirror, boolean proxyB final String type = Util.unwrapProvider(fullName); if (proxyBean || isPublic(element)) { - final var genericType = !Objects.equals(fullName, type) ? UType.parse(mirror).param0() : UType.parse(mirror); + UType uType = UType.parse(mirror); + final var genericType = !Objects.equals(fullName, type) ? uType.param0() : uType; // check if any unknown generic types are in the parameters (T,T2, etc.) final var knownType = genericType.componentTypes().stream() .flatMap(g -> Stream.concat(Stream.of(g), g.componentTypes().stream())) .noneMatch(g -> g.kind() == TypeKind.TYPEVAR); extendsTypes.add(knownType ? Util.unwrapProvider(mirror) : genericType); + if (uType.isGeneric()) { + extendsTypes.add(UType.parse(types().erasure(Util.stripProvider(mirror)))); + } extendsInjection.read(element); } @@ -257,6 +261,9 @@ private void readInterfacesOf(TypeMirror anInterface) { } } interfaceTypes.add(rawUType); + if (rawUType.isGeneric()) { + interfaceTypes.add(UType.parse(types().erasure(Util.stripProvider(anInterface)))); + } for (final TypeMirror supertype : types().directSupertypes(anInterface)) { readInterfacesOf(supertype); } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/Util.java b/inject-generator/src/main/java/io/avaje/inject/generator/Util.java index de9b34a94..473ab3933 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/Util.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/Util.java @@ -50,7 +50,7 @@ private static boolean importJavaLangSubpackage(String type) { static String classOfMethod(String method) { final int pos = method.lastIndexOf('.'); - return (pos == -1) ? "" : method.substring(0, pos); + return pos == -1 ? "" : method.substring(0, pos); } static String shortMethod(String method) { @@ -92,7 +92,7 @@ static String nestedPackageOf(String cls) { return ""; } pos = cls.lastIndexOf('.', pos - 1); - return (pos == -1) ? "" : cls.substring(0, pos); + return pos == -1 ? "" : cls.substring(0, pos); } static String unwrapProvider(String maybeProvider) { @@ -104,11 +104,7 @@ static String unwrapProvider(String maybeProvider) { } static UType unwrapProvider(TypeMirror maybeProvider) { - if (isProvider(maybeProvider.toString())) { - return UType.parse(maybeProvider).param0(); - } else { - return UType.parse(maybeProvider); - } + return UType.parse(stripProvider(maybeProvider)); } static UType unwrapProvider(UType maybeProvider) { @@ -119,6 +115,14 @@ static UType unwrapProvider(UType maybeProvider) { } } + static TypeMirror stripProvider(TypeMirror maybeProvider) { + if (isProvider(maybeProvider.toString())) { + return ((DeclaredType) maybeProvider).getTypeArguments().get(0); + } else { + return maybeProvider; + } + } + static String initLower(String name) { final StringBuilder sb = new StringBuilder(name.length()); boolean upper = true; diff --git a/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java b/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java index 531f38726..f85e0f642 100644 --- a/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java +++ b/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java @@ -5,6 +5,7 @@ import org.example.coffee.core.DuperPump; import org.example.coffee.generic.HazRepo; import org.example.coffee.generic.HazRepo$DI; +import org.example.coffee.generic.Repository; import org.example.coffee.list.BSomei; import org.example.coffee.list.Somei; import org.example.coffee.provider.AProv; @@ -115,7 +116,7 @@ void beanScope_all_includesGenericInterfaces() { .findFirst().orElse(null); assertThat(hazRepo.keys()) - .containsExactly(name(HazRepo.class), name(HazRepo$DI.TYPE_RepositoryHazLong)); + .containsExactly(name(HazRepo.class), name(HazRepo$DI.TYPE_RepositoryHazLong), name(Repository.class)); } } diff --git a/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumer.java b/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumer.java index c6e85a308..0598c39be 100644 --- a/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumer.java +++ b/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumer.java @@ -1,5 +1,7 @@ package org.example.coffee.generic; +import java.util.List; + import org.example.coffee.grind.AMusher; import jakarta.inject.Singleton; @@ -16,18 +18,29 @@ class MultiGenericConsumer { private final AMusher aMusher; - MultiGenericConsumer(Repository hazRepo, AMusher aMusher, SomeGeneric stringProcessor) { + private List> list; + + MultiGenericConsumer( + Repository hazRepo, + AMusher aMusher, + SomeGeneric stringProcessor, + List> list) { this.hazRepo = hazRepo; this.aMusher = aMusher; this.stringProcessor = stringProcessor; + this.list = list; } String findAndDo(long id) { final Haz byId = hazRepo.findById(id); - return (byId == null) ? "not found" : "found " + stringProcessor.process("" + byId.id); + return byId == null ? "not found" : "found " + stringProcessor.process("" + byId.id); } String mushString() { return aMusher.toString(); } + + List> list() { + return list; + } } diff --git a/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumerTest.java b/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumerTest.java index 33bafb5d7..42e602f63 100644 --- a/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumerTest.java +++ b/inject-test/src/test/java/org/example/coffee/generic/MultiGenericConsumerTest.java @@ -1,9 +1,10 @@ package org.example.coffee.generic; -import io.avaje.inject.xtra.ApplicationScope; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +import io.avaje.inject.xtra.ApplicationScope; public class MultiGenericConsumerTest { @@ -14,6 +15,6 @@ public void find() { assertThat(bean.findAndDo(34L)).isEqualTo("found 34 stuff"); assertThat(bean.mushString()).isNotNull(); + assertThat(bean.list()).isNotEmpty(); } - }