diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9e09472f71..31546daa6c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,6 @@ # Unreleased + - fix `GenericType` creation in parameterized classes (#2305) - add `SqlStatements#setAttachAllStatementsForCleanup`. Setting this configuration flag will attach all created statements to their handles for resource cleanup. Default is `false`. (#2293, thanks @jodastephen) - add `SqlStatements#setAttachCallbackStatementsForCleanup`. Setting this configuration flag will attach all created statements within one of the `Jdbi` callback methods to the handle. This allows code that uses the `Jdbi` callback methods to delegate resource management fully to Jdbi. This flag is set by default. (#2293, thanks @jodastephen) - fix problem when using the jdbi bom in spring projects (#2295, thanks @jedvardsson) diff --git a/core/src/main/java/org/jdbi/v3/core/generic/GenericTypes.java b/core/src/main/java/org/jdbi/v3/core/generic/GenericTypes.java index eb5445225a..1c00fa1465 100644 --- a/core/src/main/java/org/jdbi/v3/core/generic/GenericTypes.java +++ b/core/src/main/java/org/jdbi/v3/core/generic/GenericTypes.java @@ -13,6 +13,8 @@ */ package org.jdbi.v3.core.generic; +import java.lang.reflect.AnnotatedParameterizedType; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; @@ -100,7 +102,20 @@ public static Optional findGenericParameter(Type type, Class parameteri * @return the parameter on the supertype, if it is concretely defined. * @throws ArrayIndexOutOfBoundsException if n > the number of type variables the type has */ + @SuppressWarnings("PMD.AvoidDeeplyNestedIfStmts") public static Optional findGenericParameter(Type type, Class parameterizedSupertype, int n) { + if (type instanceof Class) { + // this is the same code as TypeToken#extractType + AnnotatedType t = ((Class) type).getAnnotatedSuperclass(); + if (t instanceof AnnotatedParameterizedType) { + AnnotatedParameterizedType pt = (AnnotatedParameterizedType) t; + if (((ParameterizedType) pt.getType()).getRawType() == parameterizedSupertype) { + return Optional.ofNullable(pt.getAnnotatedActualTypeArguments()[n]).map(AnnotatedType::getType); + } + } + } + + // fall back to the type reflector return Optional.ofNullable(GenericTypeReflector.getTypeParameter(type, parameterizedSupertype.getTypeParameters()[n])); } diff --git a/core/src/test/java/org/jdbi/v3/core/generic/GenericTypesTest.java b/core/src/test/java/org/jdbi/v3/core/generic/GenericTypesTest.java index d1c2bf518c..e77afbb548 100644 --- a/core/src/test/java/org/jdbi/v3/core/generic/GenericTypesTest.java +++ b/core/src/test/java/org/jdbi/v3/core/generic/GenericTypesTest.java @@ -14,6 +14,7 @@ package org.jdbi.v3.core.generic; import java.lang.reflect.Type; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -77,6 +78,17 @@ public void findMultipleGenericParameters() throws NoSuchMethodException { .contains(Void.class); } + @Test + void testGenericTypeWorksInParameterizedClasses() { + class Foo { + Type getType() { + return new GenericType>() {}.getType(); + } + } + + assertThat(new Foo<>().getType()).isNotNull(); + } + @Test public void resolveType() throws NoSuchMethodException { abstract class A {