|
|
|
@ -13,19 +13,22 @@ |
|
|
|
* See the License for the specific language governing permissions and |
|
|
|
* See the License for the specific language governing permissions and |
|
|
|
* limitations under the License. |
|
|
|
* limitations under the License. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
package org.springframework.core.convert; |
|
|
|
package org.springframework.core.convert; |
|
|
|
|
|
|
|
|
|
|
|
import java.beans.PropertyDescriptor; |
|
|
|
|
|
|
|
import java.lang.annotation.Annotation; |
|
|
|
import java.lang.annotation.Annotation; |
|
|
|
import java.lang.reflect.Field; |
|
|
|
import java.lang.reflect.Field; |
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.util.Collection; |
|
|
|
import java.util.Collection; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.HashMap; |
|
|
|
|
|
|
|
import java.util.LinkedHashMap; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.core.GenericTypeResolver; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ObjectUtils; |
|
|
|
import org.springframework.util.ObjectUtils; |
|
|
|
|
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
|
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Context about a type to convert from or to. |
|
|
|
* Context about a type to convert from or to. |
|
|
|
@ -91,11 +94,10 @@ public class TypeDescriptor { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a new type descriptor for a bean property. |
|
|
|
* Create a new type descriptor for a bean property. |
|
|
|
* Use this constructor when a target conversion point is a property on a Java class. |
|
|
|
* Use this constructor when a target conversion point is a property on a Java class. |
|
|
|
* @param beanClass the class that declares the property |
|
|
|
* @param property the property |
|
|
|
* @param property the property descriptor |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public TypeDescriptor(Class<?> beanClass, PropertyDescriptor property) { |
|
|
|
public TypeDescriptor(Property property) { |
|
|
|
this(new BeanPropertyDescriptor(beanClass, property)); |
|
|
|
this(new BeanPropertyDescriptor(property)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -140,7 +142,7 @@ public class TypeDescriptor { |
|
|
|
} |
|
|
|
} |
|
|
|
return new TypeDescriptor(mapType, keyType, valueType); |
|
|
|
return new TypeDescriptor(mapType, keyType, valueType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a type descriptor for a nested type declared within the method parameter. |
|
|
|
* Creates a type descriptor for a nested type declared within the method parameter. |
|
|
|
* For example, if the methodParameter is a List<String> and the nestingLevel is 1, the nested type descriptor will be String.class. |
|
|
|
* For example, if the methodParameter is a List<String> and the nestingLevel is 1, the nested type descriptor will be String.class. |
|
|
|
@ -182,8 +184,8 @@ public class TypeDescriptor { |
|
|
|
* @return the nested type descriptor |
|
|
|
* @return the nested type descriptor |
|
|
|
* @throws IllegalArgumentException if the property is not of a collection, array, or map type. |
|
|
|
* @throws IllegalArgumentException if the property is not of a collection, array, or map type. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static TypeDescriptor nested(Class<?> beanClass, PropertyDescriptor property, int nestingLevel) { |
|
|
|
public static TypeDescriptor nested(Property property, int nestingLevel) { |
|
|
|
return nested(new BeanPropertyDescriptor(beanClass, property), nestingLevel); |
|
|
|
return nested(new BeanPropertyDescriptor(property), nestingLevel); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -196,7 +198,7 @@ public class TypeDescriptor { |
|
|
|
public static TypeDescriptor forObject(Object source) { |
|
|
|
public static TypeDescriptor forObject(Object source) { |
|
|
|
return source != null ? valueOf(source.getClass()) : null; |
|
|
|
return source != null ? valueOf(source.getClass()) : null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Determine the declared (non-generic) type of the wrapped parameter/field. |
|
|
|
* Determine the declared (non-generic) type of the wrapped parameter/field. |
|
|
|
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL} |
|
|
|
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL} |
|
|
|
@ -230,7 +232,7 @@ public class TypeDescriptor { |
|
|
|
} |
|
|
|
} |
|
|
|
return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations); |
|
|
|
return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns the name of this type: the fully qualified class name. |
|
|
|
* Returns the name of this type: the fully qualified class name. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -288,7 +290,7 @@ public class TypeDescriptor { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// indexable type descriptor operations
|
|
|
|
// indexable type descriptor operations
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Is this type a {@link Collection} type? |
|
|
|
* Is this type a {@link Collection} type? |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -336,7 +338,7 @@ public class TypeDescriptor { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// map type descriptor operations
|
|
|
|
// map type descriptor operations
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Is this type a {@link Map} type? |
|
|
|
* Is this type a {@link Map} type? |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -406,7 +408,7 @@ public class TypeDescriptor { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// extending Object
|
|
|
|
// extending Object
|
|
|
|
|
|
|
|
|
|
|
|
public boolean equals(Object obj) { |
|
|
|
public boolean equals(Object obj) { |
|
|
|
if (this == obj) { |
|
|
|
if (this == obj) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
@ -415,17 +417,17 @@ public class TypeDescriptor { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
TypeDescriptor other = (TypeDescriptor) obj; |
|
|
|
TypeDescriptor other = (TypeDescriptor) obj; |
|
|
|
boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations()); |
|
|
|
boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType()) |
|
|
|
|
|
|
|
&& ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations()); |
|
|
|
if (!annotatedTypeEquals) { |
|
|
|
if (!annotatedTypeEquals) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (isCollection() || isArray()) { |
|
|
|
if (isCollection() || isArray()) { |
|
|
|
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType()); |
|
|
|
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType()); |
|
|
|
} |
|
|
|
} else if (isMap()) { |
|
|
|
else if (isMap()) { |
|
|
|
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) |
|
|
|
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) && ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType()); |
|
|
|
&& ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -444,13 +446,171 @@ public class TypeDescriptor { |
|
|
|
if (isMap()) { |
|
|
|
if (isMap()) { |
|
|
|
builder.append("<").append(wildcard(getMapKeyType())); |
|
|
|
builder.append("<").append(wildcard(getMapKeyType())); |
|
|
|
builder.append(", ").append(wildcard(getMapValueType())).append(">"); |
|
|
|
builder.append(", ").append(wildcard(getMapValueType())).append(">"); |
|
|
|
} |
|
|
|
} else if (isCollection()) { |
|
|
|
else if (isCollection()) { |
|
|
|
|
|
|
|
builder.append("<").append(wildcard(getElementType())).append(">"); |
|
|
|
builder.append("<").append(wildcard(getElementType())).append(">"); |
|
|
|
} |
|
|
|
} |
|
|
|
return builder.toString(); |
|
|
|
return builder.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// helper public class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static final class Property { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Class<?> objectType; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Method readMethod; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Method writeMethod; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final String name; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final MethodParameter methodParameter; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Annotation[] annotations; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Property(Class<?> objectType, Method readMethod, Method writeMethod) { |
|
|
|
|
|
|
|
this.objectType = objectType; |
|
|
|
|
|
|
|
this.readMethod = readMethod; |
|
|
|
|
|
|
|
this.writeMethod = writeMethod; |
|
|
|
|
|
|
|
this.methodParameter = resolveMethodParameter(); |
|
|
|
|
|
|
|
this.name = resolveName(); |
|
|
|
|
|
|
|
this.annotations = resolveAnnotations(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Class<?> getObjectType() { |
|
|
|
|
|
|
|
return objectType; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String getName() { |
|
|
|
|
|
|
|
return name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Class<?> getType() { |
|
|
|
|
|
|
|
return methodParameter.getParameterType(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Method getReadMethod() { |
|
|
|
|
|
|
|
return readMethod; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Method getWriteMethod() { |
|
|
|
|
|
|
|
return writeMethod; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MethodParameter getMethodParameter() { |
|
|
|
|
|
|
|
return methodParameter; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Annotation[] getAnnotations() { |
|
|
|
|
|
|
|
return annotations; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String resolveName() { |
|
|
|
|
|
|
|
if (readMethod != null) { |
|
|
|
|
|
|
|
int index = readMethod.getName().indexOf("get"); |
|
|
|
|
|
|
|
if (index != -1) { |
|
|
|
|
|
|
|
index += 3; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
index = readMethod.getName().indexOf("is"); |
|
|
|
|
|
|
|
if (index == -1) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Not a getter method"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
index += 2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return StringUtils.uncapitalize(readMethod.getName().substring(index)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
int index = writeMethod.getName().indexOf("set") + 3; |
|
|
|
|
|
|
|
if (index == -1) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Not a setter method"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return StringUtils.uncapitalize(writeMethod.getName().substring(index)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private MethodParameter resolveMethodParameter() { |
|
|
|
|
|
|
|
MethodParameter read = resolveReadMethodParameter(); |
|
|
|
|
|
|
|
MethodParameter write = resolveWriteMethodParameter(); |
|
|
|
|
|
|
|
if (read == null && write == null) { |
|
|
|
|
|
|
|
throw new IllegalStateException("Property is neither readable or writeable"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (read != null && write != null && !read.getParameterType().equals(write.getParameterType())) { |
|
|
|
|
|
|
|
throw new IllegalStateException("Read and write parameter types are not the same"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return read != null ? read : write; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private MethodParameter resolveReadMethodParameter() { |
|
|
|
|
|
|
|
if (getReadMethod() == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return resolveParameterType(new MethodParameter(getReadMethod(), -1)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private MethodParameter resolveWriteMethodParameter() { |
|
|
|
|
|
|
|
if (getWriteMethod() == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return resolveParameterType(new MethodParameter(getWriteMethod(), 0)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private MethodParameter resolveParameterType(MethodParameter parameter) { |
|
|
|
|
|
|
|
// needed to resolve generic property types that parameterized by sub-classes e.g. T getFoo();
|
|
|
|
|
|
|
|
GenericTypeResolver.resolveParameterType(parameter, getObjectType()); |
|
|
|
|
|
|
|
return parameter; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Annotation[] resolveAnnotations() { |
|
|
|
|
|
|
|
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>(); |
|
|
|
|
|
|
|
Method readMethod = getReadMethod(); |
|
|
|
|
|
|
|
if (readMethod != null) { |
|
|
|
|
|
|
|
for (Annotation ann : readMethod.getAnnotations()) { |
|
|
|
|
|
|
|
annMap.put(ann.annotationType(), ann); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Method writeMethod = getWriteMethod(); |
|
|
|
|
|
|
|
if (writeMethod != null) { |
|
|
|
|
|
|
|
for (Annotation ann : writeMethod.getAnnotations()) { |
|
|
|
|
|
|
|
annMap.put(ann.annotationType(), ann); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Field field = getField(); |
|
|
|
|
|
|
|
if (field != null) { |
|
|
|
|
|
|
|
for (Annotation ann : field.getAnnotations()) { |
|
|
|
|
|
|
|
annMap.put(ann.annotationType(), ann); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return annMap.values().toArray(new Annotation[annMap.size()]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Field getField() { |
|
|
|
|
|
|
|
String name = getName(); |
|
|
|
|
|
|
|
if (!StringUtils.hasLength(name)) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Class<?> declaringClass = declaringClass(); |
|
|
|
|
|
|
|
Field field = ReflectionUtils.findField(declaringClass, name); |
|
|
|
|
|
|
|
if (field == null) { |
|
|
|
|
|
|
|
// Same lenient fallback checking as in CachedIntrospectionResults...
|
|
|
|
|
|
|
|
field = ReflectionUtils.findField(declaringClass, |
|
|
|
|
|
|
|
name.substring(0, 1).toLowerCase() + name.substring(1)); |
|
|
|
|
|
|
|
if (field == null) { |
|
|
|
|
|
|
|
field = ReflectionUtils.findField(declaringClass, |
|
|
|
|
|
|
|
name.substring(0, 1).toUpperCase() + name.substring(1)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return field; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Class<?> declaringClass() { |
|
|
|
|
|
|
|
if (getReadMethod() != null) { |
|
|
|
|
|
|
|
return getReadMethod().getDeclaringClass(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return getWriteMethod().getDeclaringClass(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// package private
|
|
|
|
// package private
|
|
|
|
|
|
|
|
|
|
|
|
TypeDescriptor(AbstractDescriptor descriptor) { |
|
|
|
TypeDescriptor(AbstractDescriptor descriptor) { |
|
|
|
@ -464,7 +624,7 @@ public class TypeDescriptor { |
|
|
|
static Annotation[] nullSafeAnnotations(Annotation[] annotations) { |
|
|
|
static Annotation[] nullSafeAnnotations(Annotation[] annotations) { |
|
|
|
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY; |
|
|
|
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// internal constructors
|
|
|
|
// internal constructors
|
|
|
|
|
|
|
|
|
|
|
|
private TypeDescriptor(Class<?> type) { |
|
|
|
private TypeDescriptor(Class<?> type) { |
|
|
|
@ -479,7 +639,8 @@ public class TypeDescriptor { |
|
|
|
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY); |
|
|
|
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType, Annotation[] annotations) { |
|
|
|
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, |
|
|
|
|
|
|
|
TypeDescriptor mapValueType, Annotation[] annotations) { |
|
|
|
this.type = type; |
|
|
|
this.type = type; |
|
|
|
this.elementType = elementType; |
|
|
|
this.elementType = elementType; |
|
|
|
this.mapKeyType = mapKeyType; |
|
|
|
this.mapKeyType = mapKeyType; |
|
|
|
@ -494,7 +655,7 @@ public class TypeDescriptor { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return new TypeDescriptor(descriptor); |
|
|
|
return new TypeDescriptor(descriptor); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// internal helpers
|
|
|
|
// internal helpers
|
|
|
|
@ -507,7 +668,7 @@ public class TypeDescriptor { |
|
|
|
if (keyType == null) { |
|
|
|
if (keyType == null) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return keyType.isAssignableTo(targetKeyType); |
|
|
|
return keyType.isAssignableTo(targetKeyType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean collectionElementsAssignable(TypeDescriptor targetElementType) { |
|
|
|
private boolean collectionElementsAssignable(TypeDescriptor targetElementType) { |
|
|
|
@ -518,9 +679,9 @@ public class TypeDescriptor { |
|
|
|
if (elementType == null) { |
|
|
|
if (elementType == null) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return elementType.isAssignableTo(targetElementType); |
|
|
|
return elementType.isAssignableTo(targetElementType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean mapValuesAssignable(TypeDescriptor targetValueType) { |
|
|
|
private boolean mapValuesAssignable(TypeDescriptor targetValueType) { |
|
|
|
TypeDescriptor valueType = getMapValueType(); |
|
|
|
TypeDescriptor valueType = getMapValueType(); |
|
|
|
if (targetValueType == null) { |
|
|
|
if (targetValueType == null) { |
|
|
|
@ -529,21 +690,21 @@ public class TypeDescriptor { |
|
|
|
if (valueType == null) { |
|
|
|
if (valueType == null) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return valueType.isAssignableTo(targetValueType); |
|
|
|
return valueType.isAssignableTo(targetValueType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void assertCollectionOrArray() { |
|
|
|
private void assertCollectionOrArray() { |
|
|
|
if (!isCollection() && !isArray()) { |
|
|
|
if (!isCollection() && !isArray()) { |
|
|
|
throw new IllegalStateException("Not a java.util.Collection or Array"); |
|
|
|
throw new IllegalStateException("Not a java.util.Collection or Array"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void assertMap() { |
|
|
|
private void assertMap() { |
|
|
|
if (!isMap()) { |
|
|
|
if (!isMap()) { |
|
|
|
throw new IllegalStateException("Not a java.util.Map"); |
|
|
|
throw new IllegalStateException("Not a java.util.Map"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String wildcard(TypeDescriptor nestedType) { |
|
|
|
private String wildcard(TypeDescriptor nestedType) { |
|
|
|
return nestedType != null ? nestedType.toString() : "?"; |
|
|
|
return nestedType != null ? nestedType.toString() : "?"; |
|
|
|
} |
|
|
|
} |
|
|
|
|