Browse Source

Avoid mismatch between cached top-level versus nested parameter type

Issue: SPR-13755
(cherry picked from commit c909789)
pull/931/head
Juergen Hoeller 10 years ago
parent
commit
57d980130e
  1. 26
      spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
  2. 35
      spring-core/src/main/java/org/springframework/core/ResolvableType.java

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -51,28 +51,28 @@ public abstract class GenericTypeResolver {
/** /**
* Determine the target type for the given parameter specification. * Determine the target type for the given parameter specification.
* @param methodParam the method parameter specification * @param methodParameter the method parameter specification
* @return the corresponding generic parameter type * @return the corresponding generic parameter type
* @deprecated as of Spring 4.0, use {@link MethodParameter#getGenericParameterType()} * @deprecated as of Spring 4.0, use {@link MethodParameter#getGenericParameterType()}
*/ */
@Deprecated @Deprecated
public static Type getTargetType(MethodParameter methodParam) { public static Type getTargetType(MethodParameter methodParameter) {
Assert.notNull(methodParam, "MethodParameter must not be null"); Assert.notNull(methodParameter, "MethodParameter must not be null");
return methodParam.getGenericParameterType(); return methodParameter.getGenericParameterType();
} }
/** /**
* Determine the target type for the given generic parameter type. * Determine the target type for the given generic parameter type.
* @param methodParam the method parameter specification * @param methodParameter the method parameter specification
* @param clazz the class to resolve type variables against * @param implementationClass the class to resolve type variables against
* @return the corresponding generic parameter or return type * @return the corresponding generic parameter or return type
*/ */
public static Class<?> resolveParameterType(MethodParameter methodParam, Class<?> clazz) { public static Class<?> resolveParameterType(MethodParameter methodParameter, Class<?> implementationClass) {
Assert.notNull(methodParam, "MethodParameter must not be null"); Assert.notNull(methodParameter, "MethodParameter must not be null");
Assert.notNull(clazz, "Class must not be null"); Assert.notNull(implementationClass, "Class must not be null");
methodParam.setContainingClass(clazz); methodParameter.setContainingClass(implementationClass);
methodParam.setParameterType(ResolvableType.forMethodParameter(methodParam).resolve()); ResolvableType.resolveMethodParameter(methodParameter);
return methodParam.getParameterType(); return methodParameter.getParameterType();
} }
/** /**

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

@ -381,8 +381,7 @@ public final class ResolvableType implements Serializable {
return NONE; return NONE;
} }
if (this.superType == null) { if (this.superType == null) {
this.superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), this.superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
asVariableResolver());
} }
return this.superType; return this.superType;
} }
@ -399,8 +398,7 @@ public final class ResolvableType implements Serializable {
return EMPTY_TYPES_ARRAY; return EMPTY_TYPES_ARRAY;
} }
if (this.interfaces == null) { if (this.interfaces == null) {
this.interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), this.interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
asVariableResolver());
} }
return this.interfaces; return this.interfaces;
} }
@ -1102,11 +1100,11 @@ public final class ResolvableType implements Serializable {
*/ */
public static ResolvableType forMethodParameter(MethodParameter methodParameter, ResolvableType implementationType) { public static ResolvableType forMethodParameter(MethodParameter methodParameter, ResolvableType implementationType) {
Assert.notNull(methodParameter, "MethodParameter must not be null"); Assert.notNull(methodParameter, "MethodParameter must not be null");
implementationType = (implementationType == null ? forType(methodParameter.getContainingClass()) : implementationType); implementationType = (implementationType != null ? implementationType :
forType(methodParameter.getContainingClass()));
ResolvableType owner = implementationType.as(methodParameter.getDeclaringClass()); ResolvableType owner = implementationType.as(methodParameter.getDeclaringClass());
return forType(null, new MethodParameterTypeProvider(methodParameter), return forType(null, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).
owner.asVariableResolver()).getNested(methodParameter.getNestingLevel(), getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel);
methodParameter.typeIndexesPerLevel);
} }
/** /**
@ -1124,13 +1122,26 @@ public final class ResolvableType implements Serializable {
getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel); getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel);
} }
/**
* Resolve the top-level parameter type of the given {@code MethodParameter}.
* @param methodParameter the method parameter to resolve
* @since 4.1.9
* @see MethodParameter#setParameterType
*/
static void resolveMethodParameter(MethodParameter methodParameter) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass());
methodParameter.setParameterType(
forType(null, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).resolve());
}
/** /**
* Return a {@link ResolvableType} as a array of the specified {@code componentType}. * Return a {@link ResolvableType} as a array of the specified {@code componentType}.
* @param componentType the component type * @param componentType the component type
* @return a {@link ResolvableType} as an array of the specified component type * @return a {@link ResolvableType} as an array of the specified component type
*/ */
public static ResolvableType forArrayComponent(ResolvableType componentType) { public static ResolvableType forArrayComponent(ResolvableType componentType) {
Assert.notNull(componentType, "componentType must not be null"); Assert.notNull(componentType, "Component type must not be null");
Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass(); Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
return new ResolvableType(arrayClass, null, null, componentType); return new ResolvableType(arrayClass, null, null, componentType);
} }
@ -1220,7 +1231,7 @@ public final class ResolvableType implements Serializable {
/** /**
* Strategy interface used to resolve {@link TypeVariable}s. * Strategy interface used to resolve {@link TypeVariable}s.
*/ */
static interface VariableResolver extends Serializable { interface VariableResolver extends Serializable {
/** /**
* Return the source of the resolver (used for hashCode and equals). * Return the source of the resolver (used for hashCode and equals).
@ -1230,7 +1241,7 @@ public final class ResolvableType implements Serializable {
/** /**
* Resolve the specified variable. * Resolve the specified variable.
* @param variable the variable to resolve * @param variable the variable to resolve
* @return the resolved variable or {@code null} * @return the resolved variable, or {@code null} if not found
*/ */
ResolvableType resolveVariable(TypeVariable<?> variable); ResolvableType resolveVariable(TypeVariable<?> variable);
} }
@ -1362,7 +1373,7 @@ public final class ResolvableType implements Serializable {
/** /**
* The various kinds of bounds. * The various kinds of bounds.
*/ */
static enum Kind {UPPER, LOWER} enum Kind {UPPER, LOWER}
} }
} }

Loading…
Cancel
Save