Skip to content

Commit fccec21

Browse files
committed
GenericTypeResolver returns null for entirely unresolvable type arguments only
Issue: SPR-11763 (cherry picked from commit bea34ea)
1 parent 96da77e commit fccec21

File tree

3 files changed

+46
-12
lines changed

3 files changed

+46
-12
lines changed

spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,10 @@ private static Class<?> getSingleGeneric(ResolvableType resolvableType) {
243243
*/
244244
public static Class<?>[] resolveTypeArguments(Class<?> clazz, Class<?> genericIfc) {
245245
ResolvableType type = ResolvableType.forClass(clazz).as(genericIfc);
246-
if (!type.hasGenerics() || type.hasUnresolvableGenerics()) {
246+
if (!type.hasGenerics() || type.isEntirelyUnresolvable()) {
247247
return null;
248248
}
249-
return type.resolveGenerics();
249+
return type.resolveGenerics(Object.class);
250250
}
251251

252252
/**

spring-core/src/main/java/org/springframework/core/ResolvableType.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,24 @@ public boolean hasGenerics() {
416416
}
417417

418418
/**
419-
* Determine whether the underlying type has unresolvable generics:
419+
* Return {@code true} if this type contains unresolvable generics only,
420+
* that is, no substitute for any of its declared type variables.
421+
*/
422+
boolean isEntirelyUnresolvable() {
423+
if (this == NONE) {
424+
return false;
425+
}
426+
ResolvableType[] generics = getGenerics();
427+
for (ResolvableType generic : generics) {
428+
if (!generic.isUnresolvableTypeVariable() && !generic.isWildcardWithoutBounds()) {
429+
return false;
430+
}
431+
}
432+
return true;
433+
}
434+
435+
/**
436+
* Determine whether the underlying type has any unresolvable generics:
420437
* either through an unresolvable type variable on the type itself
421438
* or through implementing a generic interface in a raw fashion,
422439
* i.e. without substituting that interface's type variables.
@@ -634,8 +651,8 @@ public Class<?>[] resolveGenerics(Class<?> fallback) {
634651
/**
635652
* Convenience method that will {@link #getGeneric(int...) get} and
636653
* {@link #resolve() resolve} a specific generic parameters.
637-
* @param indexes the indexes that refer to the generic parameter (may be omitted to
638-
* return the first generic)
654+
* @param indexes the indexes that refer to the generic parameter
655+
* (may be omitted to return the first generic)
639656
* @return a resolved {@link Class} or {@code null}
640657
* @see #getGeneric(int...)
641658
* @see #resolve()
@@ -645,11 +662,11 @@ public Class<?> resolveGeneric(int... indexes) {
645662
}
646663

647664
/**
648-
* Resolve this type to a {@link java.lang.Class}, returning {@code null} if the type
649-
* cannot be resolved. This method will consider bounds of {@link TypeVariable}s and
650-
* {@link WildcardType}s if direct resolution fails; however, bounds of
651-
* {@code Object.class} will be ignored.
652-
* @return the resolved {@link Class} or {@code null}
665+
* Resolve this type to a {@link java.lang.Class}, returning {@code null}
666+
* if the type cannot be resolved. This method will consider bounds of
667+
* {@link TypeVariable}s and {@link WildcardType}s if direct resolution fails;
668+
* however, bounds of {@code Object.class} will be ignored.
669+
* @return the resolved {@link Class}, or {@code null} if not resolvable
653670
* @see #resolve(Class)
654671
* @see #resolveGeneric(int...)
655672
* @see #resolveGenerics()

spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.core;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021
import java.lang.reflect.Type;
2122
import java.lang.reflect.TypeVariable;
@@ -166,11 +167,21 @@ public void getGenericsOnArrayFromParamCannotBeResolved() throws Exception {
166167
public void getGenericsOnArrayFromReturnCannotBeResolved() throws Exception {
167168
// SPR-11044
168169
Class<?> resolved = GenericTypeResolver.resolveReturnType(
169-
WithArrayBase.class.getDeclaredMethod("array", Object[].class),
170-
WithArray.class);
170+
WithArrayBase.class.getDeclaredMethod("array", Object[].class), WithArray.class);
171171
assertThat(resolved, equalTo((Class) Object[].class));
172172
}
173173

174+
@Test
175+
public void resolveIncompleteTypeVariables() {
176+
// SPR-11763
177+
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(IdFixingRepository.class, Repository.class);
178+
assertNotNull(resolved);
179+
assertEquals(2, resolved.length);
180+
assertEquals(Object.class, resolved[0]);
181+
assertEquals(Long.class, resolved[1]);
182+
}
183+
184+
174185
public interface MyInterfaceType<T> {
175186
}
176187

@@ -314,4 +325,10 @@ static abstract class WithArrayBase<T> {
314325
static abstract class WithArray<T> extends WithArrayBase<T> {
315326
}
316327

328+
interface Repository<T, ID extends Serializable> {
329+
}
330+
331+
interface IdFixingRepository<T> extends Repository<T, Long> {
332+
}
333+
317334
}

0 commit comments

Comments
 (0)