full support for arbitrary nesting of collections in fields (SPR-8394); proper type detection in nested collections within arrays
This commit is contained in:
parent
15e009f3a0
commit
d940811d8b
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -75,7 +75,7 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getCollectionFieldType(Field collectionField) {
|
||||
return getGenericFieldType(collectionField, Collection.class, 0, 1);
|
||||
return getGenericFieldType(collectionField, Collection.class, 0, null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,7 +87,21 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getCollectionFieldType(Field collectionField, int nestingLevel) {
|
||||
return getGenericFieldType(collectionField, Collection.class, 0, nestingLevel);
|
||||
return getGenericFieldType(collectionField, Collection.class, 0, null, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic element type of the given Collection field.
|
||||
* @param collectionField the collection field to introspect
|
||||
* @param nestingLevel the nesting level of the target type
|
||||
* (typically 1; e.g. in case of a List of Lists, 1 would indicate the
|
||||
* nested List, whereas 2 would indicate the element of the nested List)
|
||||
* @param typeIndexesPerLevel Map keyed by nesting level, with each value
|
||||
* expressing the type index for traversal at that level
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getCollectionFieldType(Field collectionField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
return getGenericFieldType(collectionField, Collection.class, 0, typeIndexesPerLevel, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +110,7 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapKeyFieldType(Field mapField) {
|
||||
return getGenericFieldType(mapField, Map.class, 0, 1);
|
||||
return getGenericFieldType(mapField, Map.class, 0, null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -108,7 +122,21 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapKeyFieldType(Field mapField, int nestingLevel) {
|
||||
return getGenericFieldType(mapField, Map.class, 0, nestingLevel);
|
||||
return getGenericFieldType(mapField, Map.class, 0, null, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic key type of the given Map field.
|
||||
* @param mapField the map field to introspect
|
||||
* @param nestingLevel the nesting level of the target type
|
||||
* (typically 1; e.g. in case of a List of Lists, 1 would indicate the
|
||||
* nested List, whereas 2 would indicate the element of the nested List)
|
||||
* @param typeIndexesPerLevel Map keyed by nesting level, with each value
|
||||
* expressing the type index for traversal at that level
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapKeyFieldType(Field mapField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
return getGenericFieldType(mapField, Map.class, 0, typeIndexesPerLevel, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -117,7 +145,7 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapValueFieldType(Field mapField) {
|
||||
return getGenericFieldType(mapField, Map.class, 1, 1);
|
||||
return getGenericFieldType(mapField, Map.class, 1, null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,7 +157,21 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapValueFieldType(Field mapField, int nestingLevel) {
|
||||
return getGenericFieldType(mapField, Map.class, 1, nestingLevel);
|
||||
return getGenericFieldType(mapField, Map.class, 1, null, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic value type of the given Map field.
|
||||
* @param mapField the map field to introspect
|
||||
* @param nestingLevel the nesting level of the target type
|
||||
* (typically 1; e.g. in case of a List of Lists, 1 would indicate the
|
||||
* nested List, whereas 2 would indicate the element of the nested List)
|
||||
* @param typeIndexesPerLevel Map keyed by nesting level, with each value
|
||||
* expressing the type index for traversal at that level
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public static Class<?> getMapValueFieldType(Field mapField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
return getGenericFieldType(mapField, Map.class, 1, typeIndexesPerLevel, nestingLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -234,8 +276,8 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> getGenericParameterType(MethodParameter methodParam, Class<?> source, int typeIndex) {
|
||||
return extractType(methodParam, GenericTypeResolver.getTargetType(methodParam),
|
||||
source, typeIndex, methodParam.getNestingLevel(), 1);
|
||||
return extractType(GenericTypeResolver.getTargetType(methodParam), source, typeIndex,
|
||||
methodParam.typeVariableMap, methodParam.typeIndexesPerLevel, methodParam.getNestingLevel(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,8 +289,9 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @param nestingLevel the nesting level of the target type
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> getGenericFieldType(Field field, Class<?> source, int typeIndex, int nestingLevel) {
|
||||
return extractType(null, field.getGenericType(), source, typeIndex, nestingLevel, 1);
|
||||
private static Class<?> getGenericFieldType(Field field, Class<?> source, int typeIndex,
|
||||
Map<Integer, Integer> typeIndexesPerLevel, int nestingLevel) {
|
||||
return extractType(field.getGenericType(), source, typeIndex, null, typeIndexesPerLevel, nestingLevel, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -261,12 +304,11 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> getGenericReturnType(Method method, Class<?> source, int typeIndex, int nestingLevel) {
|
||||
return extractType(null, method.getGenericReturnType(), source, typeIndex, nestingLevel, 1);
|
||||
return extractType(method.getGenericReturnType(), source, typeIndex, null, null, nestingLevel, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the generic type from the given Type object.
|
||||
* @param methodParam the method parameter specification
|
||||
* @param type the Type to check
|
||||
* @param source the source collection/map Class that we check
|
||||
* @param typeIndex the index of the actual type argument
|
||||
|
|
@ -274,22 +316,28 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @param currentLevel the current nested level
|
||||
* @return the generic type as Class, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> extractType(
|
||||
MethodParameter methodParam, Type type, Class<?> source, int typeIndex, int nestingLevel, int currentLevel) {
|
||||
private static Class<?> extractType(Type type, Class<?> source, int typeIndex,
|
||||
Map<TypeVariable, Type> typeVariableMap, Map<Integer, Integer> typeIndexesPerLevel,
|
||||
int nestingLevel, int currentLevel) {
|
||||
|
||||
Type resolvedType = type;
|
||||
if (type instanceof TypeVariable && methodParam != null && methodParam.typeVariableMap != null) {
|
||||
Type mappedType = methodParam.typeVariableMap.get((TypeVariable) type);
|
||||
if (type instanceof TypeVariable && typeVariableMap != null) {
|
||||
Type mappedType = typeVariableMap.get((TypeVariable) type);
|
||||
if (mappedType != null) {
|
||||
resolvedType = mappedType;
|
||||
}
|
||||
}
|
||||
if (resolvedType instanceof ParameterizedType) {
|
||||
return extractTypeFromParameterizedType(
|
||||
methodParam, (ParameterizedType) resolvedType, source, typeIndex, nestingLevel, currentLevel);
|
||||
return extractTypeFromParameterizedType((ParameterizedType) resolvedType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
|
||||
nestingLevel, currentLevel);
|
||||
}
|
||||
else if (resolvedType instanceof Class) {
|
||||
return extractTypeFromClass(methodParam, (Class) resolvedType, source, typeIndex, nestingLevel, currentLevel);
|
||||
return extractTypeFromClass((Class) resolvedType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
|
||||
nestingLevel, currentLevel);
|
||||
}
|
||||
else if (resolvedType instanceof GenericArrayType) {
|
||||
Type compType = ((GenericArrayType) resolvedType).getGenericComponentType();
|
||||
return extractType(compType, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, currentLevel + 1);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
|
|
@ -298,7 +346,6 @@ public abstract class GenericCollectionTypeResolver {
|
|||
|
||||
/**
|
||||
* Extract the generic type from the given ParameterizedType object.
|
||||
* @param methodParam the method parameter specification
|
||||
* @param ptype the ParameterizedType to check
|
||||
* @param source the expected raw source type (can be <code>null</code>)
|
||||
* @param typeIndex the index of the actual type argument
|
||||
|
|
@ -306,8 +353,9 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @param currentLevel the current nested level
|
||||
* @return the generic type as Class, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> extractTypeFromParameterizedType(MethodParameter methodParam,
|
||||
ParameterizedType ptype, Class<?> source, int typeIndex, int nestingLevel, int currentLevel) {
|
||||
private static Class<?> extractTypeFromParameterizedType(ParameterizedType ptype, Class<?> source, int typeIndex,
|
||||
Map<TypeVariable, Type> typeVariableMap, Map<Integer, Integer> typeIndexesPerLevel,
|
||||
int nestingLevel, int currentLevel) {
|
||||
|
||||
if (!(ptype.getRawType() instanceof Class)) {
|
||||
return null;
|
||||
|
|
@ -316,17 +364,17 @@ public abstract class GenericCollectionTypeResolver {
|
|||
Type[] paramTypes = ptype.getActualTypeArguments();
|
||||
if (nestingLevel - currentLevel > 0) {
|
||||
int nextLevel = currentLevel + 1;
|
||||
Integer currentTypeIndex = (methodParam != null ? methodParam.getTypeIndexForLevel(nextLevel) : null);
|
||||
Integer currentTypeIndex = (typeIndexesPerLevel != null ? typeIndexesPerLevel.get(nextLevel) : null);
|
||||
// Default is last parameter type: Collection element or Map value.
|
||||
int indexToUse = (currentTypeIndex != null ? currentTypeIndex : paramTypes.length - 1);
|
||||
Type paramType = paramTypes[indexToUse];
|
||||
return extractType(methodParam, paramType, source, typeIndex, nestingLevel, nextLevel);
|
||||
return extractType(paramType, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, nextLevel);
|
||||
}
|
||||
if (source != null && !source.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
Class fromSuperclassOrInterface =
|
||||
extractTypeFromClass(methodParam, rawType, source, typeIndex, nestingLevel, currentLevel);
|
||||
Class fromSuperclassOrInterface = extractTypeFromClass(rawType, source, typeIndex, typeVariableMap, typeIndexesPerLevel,
|
||||
nestingLevel, currentLevel);
|
||||
if (fromSuperclassOrInterface != null) {
|
||||
return fromSuperclassOrInterface;
|
||||
}
|
||||
|
|
@ -334,8 +382,8 @@ public abstract class GenericCollectionTypeResolver {
|
|||
return null;
|
||||
}
|
||||
Type paramType = paramTypes[typeIndex];
|
||||
if (paramType instanceof TypeVariable && methodParam != null && methodParam.typeVariableMap != null) {
|
||||
Type mappedType = methodParam.typeVariableMap.get((TypeVariable) paramType);
|
||||
if (paramType instanceof TypeVariable && typeVariableMap != null) {
|
||||
Type mappedType = typeVariableMap.get((TypeVariable) paramType);
|
||||
if (mappedType != null) {
|
||||
paramType = mappedType;
|
||||
}
|
||||
|
|
@ -378,12 +426,11 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @return the generic type as Class, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> extractTypeFromClass(Class<?> clazz, Class<?> source, int typeIndex) {
|
||||
return extractTypeFromClass(null, clazz, source, typeIndex, 1, 1);
|
||||
return extractTypeFromClass(clazz, source, typeIndex, null, null, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the generic type from the given Class object.
|
||||
* @param methodParam the method parameter specification
|
||||
* @param clazz the Class to check
|
||||
* @param source the expected raw source type (can be <code>null</code>)
|
||||
* @param typeIndex the index of the actual type argument
|
||||
|
|
@ -391,14 +438,16 @@ public abstract class GenericCollectionTypeResolver {
|
|||
* @param currentLevel the current nested level
|
||||
* @return the generic type as Class, or <code>null</code> if none
|
||||
*/
|
||||
private static Class<?> extractTypeFromClass(
|
||||
MethodParameter methodParam, Class<?> clazz, Class<?> source, int typeIndex, int nestingLevel, int currentLevel) {
|
||||
private static Class<?> extractTypeFromClass(Class<?> clazz, Class<?> source, int typeIndex,
|
||||
Map<TypeVariable, Type> typeVariableMap, Map<Integer, Integer> typeIndexesPerLevel,
|
||||
int nestingLevel, int currentLevel) {
|
||||
|
||||
if (clazz.getName().startsWith("java.util.")) {
|
||||
return null;
|
||||
}
|
||||
if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) {
|
||||
return extractType(methodParam, clazz.getGenericSuperclass(), source, typeIndex, nestingLevel, currentLevel);
|
||||
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap, typeIndexesPerLevel,
|
||||
nestingLevel, currentLevel);
|
||||
}
|
||||
Type[] ifcs = clazz.getGenericInterfaces();
|
||||
if (ifcs != null) {
|
||||
|
|
@ -408,7 +457,7 @@ public abstract class GenericCollectionTypeResolver {
|
|||
rawType = ((ParameterizedType) ifc).getRawType();
|
||||
}
|
||||
if (rawType instanceof Class && isIntrospectionCandidate((Class) rawType)) {
|
||||
return extractType(methodParam, ifc, source, typeIndex, nestingLevel, currentLevel);
|
||||
return extractType(ifc, source, typeIndex, typeVariableMap, typeIndexesPerLevel, nestingLevel, currentLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,12 +60,11 @@ public class MethodParameter {
|
|||
private int nestingLevel = 1;
|
||||
|
||||
/** Map from Integer level to Integer type index */
|
||||
private Map<Integer,Integer> typeIndexesPerLevel;
|
||||
Map<Integer, Integer> typeIndexesPerLevel;
|
||||
|
||||
Map<TypeVariable, Type> typeVariableMap;
|
||||
|
||||
private int hash;
|
||||
|
||||
private int hash = 0;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -440,12 +439,13 @@ public class MethodParameter {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hash;
|
||||
int result = this.hash;
|
||||
if (result == 0) {
|
||||
result = getMember().hashCode();
|
||||
result = 31 * result + parameterIndex;
|
||||
hash = result;
|
||||
result = 31 * result + this.parameterIndex;
|
||||
this.hash = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,17 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.convert;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @since 3.1
|
||||
*/
|
||||
abstract class AbstractDescriptor {
|
||||
|
||||
private final Class<?> type;
|
||||
|
|
@ -37,11 +42,13 @@ abstract class AbstractDescriptor {
|
|||
public TypeDescriptor getElementTypeDescriptor() {
|
||||
if (isCollection()) {
|
||||
Class<?> elementType = resolveCollectionElementType();
|
||||
return elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null;
|
||||
} else if (isArray()) {
|
||||
return (elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null);
|
||||
}
|
||||
else if (isArray()) {
|
||||
Class<?> elementType = getType().getComponentType();
|
||||
return new TypeDescriptor(nested(elementType, 0));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +57,8 @@ abstract class AbstractDescriptor {
|
|||
if (isMap()) {
|
||||
Class<?> keyType = resolveMapKeyType();
|
||||
return keyType != null ? new TypeDescriptor(nested(keyType, 0)) : null;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +67,8 @@ abstract class AbstractDescriptor {
|
|||
if (isMap()) {
|
||||
Class<?> valueType = resolveMapValueType();
|
||||
return valueType != null ? new TypeDescriptor(nested(valueType, 1)) : null;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -70,12 +79,15 @@ abstract class AbstractDescriptor {
|
|||
if (isCollection()) {
|
||||
Class<?> elementType = resolveCollectionElementType();
|
||||
return elementType != null ? nested(elementType, 0) : null;
|
||||
} else if (isArray()) {
|
||||
}
|
||||
else if (isArray()) {
|
||||
return nested(getType().getComponentType(), 0);
|
||||
} else if (isMap()) {
|
||||
}
|
||||
else if (isMap()) {
|
||||
Class<?> mapValueType = resolveMapValueType();
|
||||
return mapValueType != null ? nested(mapValueType, 1) : null;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Not a collection, array, or map: cannot resolve nested value types");
|
||||
}
|
||||
}
|
||||
|
|
@ -104,4 +116,4 @@ abstract class AbstractDescriptor {
|
|||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.convert;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @since 3.1
|
||||
*/
|
||||
class ClassDescriptor extends AbstractDescriptor {
|
||||
|
||||
ClassDescriptor(Class<?> type) {
|
||||
|
|
@ -48,4 +53,4 @@ class ClassDescriptor extends AbstractDescriptor {
|
|||
return new ClassDescriptor(type);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,23 +13,44 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.convert;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @since 3.1
|
||||
*/
|
||||
class FieldDescriptor extends AbstractDescriptor {
|
||||
|
||||
private final Field field;
|
||||
|
||||
private final int nestingLevel;
|
||||
|
||||
private Map<Integer, Integer> typeIndexesPerLevel;
|
||||
|
||||
|
||||
public FieldDescriptor(Field field) {
|
||||
this(field.getType(), field, 1, 0);
|
||||
super(field.getType());
|
||||
this.field = field;
|
||||
this.nestingLevel = 1;
|
||||
}
|
||||
|
||||
private FieldDescriptor(Class<?> type, Field field, int nestingLevel, int typeIndex, Map<Integer, Integer> typeIndexesPerLevel) {
|
||||
super(type);
|
||||
this.field = field;
|
||||
this.nestingLevel = nestingLevel;
|
||||
this.typeIndexesPerLevel = typeIndexesPerLevel;
|
||||
this.typeIndexesPerLevel.put(nestingLevel, typeIndex);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return TypeDescriptor.nullSafeAnnotations(field.getAnnotations());
|
||||
|
|
@ -37,31 +58,25 @@ class FieldDescriptor extends AbstractDescriptor {
|
|||
|
||||
@Override
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel);
|
||||
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel);
|
||||
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel);
|
||||
return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel, this.typeIndexesPerLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractDescriptor nested(Class<?> type, int typeIndex) {
|
||||
return new FieldDescriptor(type, this.field, this.nestingLevel + 1, typeIndex);
|
||||
if (this.typeIndexesPerLevel == null) {
|
||||
this.typeIndexesPerLevel = new HashMap<Integer, Integer>(4);
|
||||
}
|
||||
return new FieldDescriptor(type, this.field, this.nestingLevel + 1, typeIndex, this.typeIndexesPerLevel);
|
||||
}
|
||||
|
||||
// internal
|
||||
|
||||
private FieldDescriptor(Class<?> type, Field field, int nestingLevel, int typeIndex) {
|
||||
super(type);
|
||||
this.field = field;
|
||||
this.nestingLevel = nestingLevel;
|
||||
// TODO typeIndex is not preserved at current nestingLevel is not preserved: see SPR-8394
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.convert;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
|
@ -20,41 +21,52 @@ import java.lang.annotation.Annotation;
|
|||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
* @since 3.1
|
||||
*/
|
||||
class ParameterDescriptor extends AbstractDescriptor {
|
||||
|
||||
private final MethodParameter methodParameter;
|
||||
|
||||
|
||||
public ParameterDescriptor(MethodParameter methodParameter) {
|
||||
super(methodParameter.getParameterType());
|
||||
if (methodParameter.getNestingLevel() != 1) {
|
||||
throw new IllegalArgumentException("The MethodParameter argument must have its nestingLevel set to 1");
|
||||
throw new IllegalArgumentException("MethodParameter argument must have its nestingLevel set to 1");
|
||||
}
|
||||
this.methodParameter = methodParameter;
|
||||
}
|
||||
|
||||
private ParameterDescriptor(Class<?> type, MethodParameter methodParameter) {
|
||||
super(type);
|
||||
this.methodParameter = methodParameter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
if (methodParameter.getParameterIndex() == -1) {
|
||||
return TypeDescriptor.nullSafeAnnotations(methodParameter.getMethodAnnotations());
|
||||
if (this.methodParameter.getParameterIndex() == -1) {
|
||||
return TypeDescriptor.nullSafeAnnotations(this.methodParameter.getMethodAnnotations());
|
||||
}
|
||||
else {
|
||||
return TypeDescriptor.nullSafeAnnotations(methodParameter.getParameterAnnotations());
|
||||
return TypeDescriptor.nullSafeAnnotations(this.methodParameter.getParameterAnnotations());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
|
||||
return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -65,11 +77,4 @@ class ParameterDescriptor extends AbstractDescriptor {
|
|||
return new ParameterDescriptor(type, methodParameter);
|
||||
}
|
||||
|
||||
// internal
|
||||
|
||||
private ParameterDescriptor(Class<?> type, MethodParameter methodParameter) {
|
||||
super(type);
|
||||
this.methodParameter = methodParameter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue