diff --git a/VERSION.txt b/VERSION.txt index 1b71189..4d85e08 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -5,7 +5,8 @@ Release notes: 1.8.0 (not yet released) -- +#53: Allow for subtype resolution with unknown generics + (reported by Carsten W, @CarstenWickner) 1.7.1 (26-Sep-2025) diff --git a/src/main/java/com/fasterxml/classmate/TypeResolver.java b/src/main/java/com/fasterxml/classmate/TypeResolver.java index 48c174a..b37ecab 100644 --- a/src/main/java/com/fasterxml/classmate/TypeResolver.java +++ b/src/main/java/com/fasterxml/classmate/TypeResolver.java @@ -422,10 +422,28 @@ private ResolvedType _constructType(ClassStack context, Class rawType, TypeBi ResolvedType elementType = _fromAny(context, rawType.getComponentType(), typeBindings); return new ResolvedArrayType(rawType, typeBindings, elementType); } - // Work-around/fix for [#33]: if the type has no type parameters, don't include - // typeBindings in the ResolvedType - if (!typeBindings.isEmpty() && rawType.getTypeParameters().length == 0) { - typeBindings = TypeBindings.emptyBindings(); + final TypeVariable[] rawTypeParameters = rawType.getTypeParameters(); + // [classmate#53]: Handle raw generic types - resolve type parameters to their bounds + if (typeBindings.isEmpty()) { + if (rawTypeParameters.length > 0) { + ResolvedType[] types = new ResolvedType[rawTypeParameters.length]; + for (int i = 0; i < rawTypeParameters.length; ++i) { + // Resolve each type parameter to its bound (similar to _fromVariable) + TypeVariable var = rawTypeParameters[i]; + String name = var.getName(); + // Avoid self-reference cycles by marking as unbound during resolution + TypeBindings tempBindings = typeBindings.withUnboundVariable(name); + Type[] bounds = var.getBounds(); + types[i] = _fromAny(context, bounds[0], tempBindings); + } + typeBindings = TypeBindings.create(rawType, types); + } + } else { + // Work-around/fix for [classmate#33]: if the type has no type parameters, + // don't include typeBindings in the ResolvedType + if (rawTypeParameters.length == 0) { + typeBindings = TypeBindings.emptyBindings(); + } } // For other types super interfaces are needed... if (rawType.isInterface()) { diff --git a/src/test/java/com/fasterxml/classmate/TestTypeResolver53.java b/src/test/java/com/fasterxml/classmate/TestTypeResolver53.java new file mode 100644 index 0000000..d771ce1 --- /dev/null +++ b/src/test/java/com/fasterxml/classmate/TestTypeResolver53.java @@ -0,0 +1,76 @@ +package com.fasterxml.classmate; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import com.fasterxml.classmate.BaseTest; +import com.fasterxml.classmate.ResolvedType; +import com.fasterxml.classmate.TypeResolver; + +// for [classmate#53]: Raw Comparator +public class TestTypeResolver53 extends BaseTest +{ + @SuppressWarnings("rawtypes") + static abstract class Comparator53 implements Comparator { } + + @SuppressWarnings("rawtypes") + static abstract class Map53 implements Map { } + + @SuppressWarnings("rawtypes") + static abstract class BoundedComparable implements Comparable { } + + @SuppressWarnings("rawtypes") + static abstract class BoundedRaw extends BoundedComparable { } + + static abstract class NestedRaw extends java.util.ArrayList { } + + protected final TypeResolver RESOLVER = new TypeResolver(); + + // [classmate#53] Problem with Raw types - single type parameter + public void testResolvingRawType() { + ResolvedType rt = RESOLVER.resolve(Comparator53.class); + List params = rt.typeParametersFor(Comparator.class); + assertEquals(Arrays.asList(RESOLVER.resolve(Object.class)), + params); + } + + // [classmate#53] Raw type with multiple type parameters (Map) + public void testRawTypeMultipleParameters() { + ResolvedType rt = RESOLVER.resolve(Map53.class); + List params = rt.typeParametersFor(Map.class); + assertEquals(Arrays.asList( + RESOLVER.resolve(Object.class), + RESOLVER.resolve(Object.class)), + params); + } + + // [classmate#53] Raw type with bounded type parameter + public void testRawTypeWithBoundedParameter() { + ResolvedType rt = RESOLVER.resolve(BoundedRaw.class); + List params = rt.typeParametersFor(Comparable.class); + // BoundedComparable implements Comparable, used raw + // Type parameter T has bound Number, so should resolve to Number + assertEquals(Arrays.asList(RESOLVER.resolve(Number.class)), + params); + } + + // [classmate#53] Nested raw types (List where Map is raw) + public void testNestedRawType() { + ResolvedType rt = RESOLVER.resolve(NestedRaw.class); + List params = rt.typeParametersFor(java.util.ArrayList.class); + assertEquals(1, params.size()); + + // The type parameter should be Map (raw), which should have its own parameters + ResolvedType mapType = params.get(0); + assertEquals(Map.class, mapType.getErasedType()); + + // The raw Map should have Object,Object as its type parameters + List mapParams = mapType.getTypeParameters(); + assertEquals(Arrays.asList( + RESOLVER.resolve(Object.class), + RESOLVER.resolve(Object.class)), + mapParams); + } +} diff --git a/src/test/java/com/fasterxml/classmate/failing/TestTypeResolver53.java b/src/test/java/com/fasterxml/classmate/failing/TestTypeResolver53.java deleted file mode 100644 index 01eedd1..0000000 --- a/src/test/java/com/fasterxml/classmate/failing/TestTypeResolver53.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.fasterxml.classmate.failing; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import com.fasterxml.classmate.BaseTest; -import com.fasterxml.classmate.ResolvedType; -import com.fasterxml.classmate.TypeResolver; - -// for [classmate#53]: Raw Comparator -public class TestTypeResolver53 extends BaseTest -{ - @SuppressWarnings("rawtypes") - static abstract class Comparator53 implements Comparator { } - - protected final TypeResolver RESOLVER = new TypeResolver(); - - // [classmate#53] Problem with Raw types - public void testResolvingRawType() { - ResolvedType rt = RESOLVER.resolve(Comparator53.class); - List params = rt.typeParametersFor(Comparator.class); - assertEquals(Arrays.asList(RESOLVER.resolve(Object.class)), - params); - } -}