|
|
|
@ -123,27 +123,27 @@ public final class ResolvableType implements Serializable { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Private constructor used to create a new {@link ResolvableType} for resolution purposes. |
|
|
|
* Private constructor used to create a new {@link ResolvableType} for cache key purposes. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private ResolvableType( |
|
|
|
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) { |
|
|
|
Type type, TypeProvider typeProvider, VariableResolver variableResolver, ResolvableType componentType) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.type = type; |
|
|
|
this.type = type; |
|
|
|
this.typeProvider = typeProvider; |
|
|
|
this.typeProvider = typeProvider; |
|
|
|
this.variableResolver = variableResolver; |
|
|
|
this.variableResolver = variableResolver; |
|
|
|
this.componentType = componentType; |
|
|
|
this.componentType = null; |
|
|
|
this.resolved = resolveClass(); |
|
|
|
this.resolved = null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Private constructor used to create a new {@link ResolvableType} for cache key purposes. |
|
|
|
* Private constructor used to create a new {@link ResolvableType} for resolution purposes. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) { |
|
|
|
private ResolvableType( |
|
|
|
|
|
|
|
Type type, TypeProvider typeProvider, VariableResolver variableResolver, ResolvableType componentType) { |
|
|
|
|
|
|
|
|
|
|
|
this.type = type; |
|
|
|
this.type = type; |
|
|
|
this.typeProvider = typeProvider; |
|
|
|
this.typeProvider = typeProvider; |
|
|
|
this.variableResolver = variableResolver; |
|
|
|
this.variableResolver = variableResolver; |
|
|
|
this.componentType = null; |
|
|
|
this.componentType = componentType; |
|
|
|
this.resolved = null; |
|
|
|
this.resolved = resolveClass(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -598,7 +598,7 @@ public final class ResolvableType implements Serializable { |
|
|
|
return EMPTY_TYPES_ARRAY; |
|
|
|
return EMPTY_TYPES_ARRAY; |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.generics == null) { |
|
|
|
if (this.generics == null) { |
|
|
|
if (this.type instanceof Class<?>) { |
|
|
|
if (this.type instanceof Class) { |
|
|
|
Class<?> typeClass = (Class<?>) this.type; |
|
|
|
Class<?> typeClass = (Class<?>) this.type; |
|
|
|
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver); |
|
|
|
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -691,7 +691,7 @@ public final class ResolvableType implements Serializable { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Class<?> resolveClass() { |
|
|
|
private Class<?> resolveClass() { |
|
|
|
if (this.type instanceof Class<?> || this.type == null) { |
|
|
|
if (this.type instanceof Class || this.type == null) { |
|
|
|
return (Class<?>) this.type; |
|
|
|
return (Class<?>) this.type; |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.type instanceof GenericArrayType) { |
|
|
|
if (this.type instanceof GenericArrayType) { |
|
|
|
@ -762,48 +762,20 @@ public final class ResolvableType implements Serializable { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return a String representation of this type in its fully resolved form |
|
|
|
|
|
|
|
* (including any generic parameters). |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
if (isArray()) { |
|
|
|
|
|
|
|
return getComponentType() + "[]"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (this.resolved == null) { |
|
|
|
|
|
|
|
return "?"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (this.type instanceof TypeVariable) { |
|
|
|
|
|
|
|
TypeVariable<?> variable = (TypeVariable<?>) this.type; |
|
|
|
|
|
|
|
if (this.variableResolver == null || this.variableResolver.resolveVariable(variable) == null) { |
|
|
|
|
|
|
|
// Don't bother with variable boundaries for toString()...
|
|
|
|
|
|
|
|
// Can cause infinite recursions in case of self-references
|
|
|
|
|
|
|
|
return "?"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
StringBuilder result = new StringBuilder(this.resolved.getName()); |
|
|
|
|
|
|
|
if (hasGenerics()) { |
|
|
|
|
|
|
|
result.append('<'); |
|
|
|
|
|
|
|
result.append(StringUtils.arrayToDelimitedString(getGenerics(), ", ")); |
|
|
|
|
|
|
|
result.append('>'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public boolean equals(Object obj) { |
|
|
|
public boolean equals(Object other) { |
|
|
|
if (this == obj) { |
|
|
|
if (this == other) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!(obj instanceof ResolvableType)) { |
|
|
|
if (!(other instanceof ResolvableType)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
ResolvableType other = (ResolvableType) obj; |
|
|
|
ResolvableType otherType = (ResolvableType) other; |
|
|
|
return (ObjectUtils.nullSafeEquals(this.type, other.type) && |
|
|
|
return (ObjectUtils.nullSafeEquals(this.type, otherType.type) && |
|
|
|
ObjectUtils.nullSafeEquals(getSource(), other.getSource()) && |
|
|
|
ObjectUtils.nullSafeEquals(getSource(), otherType.getSource()) && |
|
|
|
variableResolverSourceEquals(other.variableResolver) && |
|
|
|
variableResolverSourceEquals(otherType.variableResolver) && |
|
|
|
ObjectUtils.nullSafeEquals(this.componentType, other.componentType)); |
|
|
|
ObjectUtils.nullSafeEquals(this.componentType, otherType.componentType)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@ -815,23 +787,6 @@ public final class ResolvableType implements Serializable { |
|
|
|
return hashCode; |
|
|
|
return hashCode; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Custom serialization support for {@link #NONE}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Object readResolve() throws ObjectStreamException { |
|
|
|
|
|
|
|
return (this.type == null ? NONE : this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Adapts this {@link ResolvableType} to a {@link VariableResolver}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
VariableResolver asVariableResolver() { |
|
|
|
|
|
|
|
if (this == NONE) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return new DefaultVariableResolver(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean variableResolverSourceEquals(VariableResolver other) { |
|
|
|
private boolean variableResolverSourceEquals(VariableResolver other) { |
|
|
|
if (this.variableResolver == null) { |
|
|
|
if (this.variableResolver == null) { |
|
|
|
return (other == null); |
|
|
|
return (other == null); |
|
|
|
@ -850,17 +805,59 @@ public final class ResolvableType implements Serializable { |
|
|
|
return hashCode; |
|
|
|
return hashCode; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) { |
|
|
|
/** |
|
|
|
ResolvableType[] result = new ResolvableType[types.length]; |
|
|
|
* Adapts this {@link ResolvableType} to a {@link VariableResolver}. |
|
|
|
for (int i = 0; i < types.length; i++) { |
|
|
|
*/ |
|
|
|
result[i] = forType(types[i], owner); |
|
|
|
VariableResolver asVariableResolver() { |
|
|
|
|
|
|
|
if (this == NONE) { |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
return new DefaultVariableResolver(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Custom serialization support for {@link #NONE}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Object readResolve() throws ObjectStreamException { |
|
|
|
|
|
|
|
return (this.type == null ? NONE : this); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class}. For example |
|
|
|
* Return a String representation of this type in its fully resolved form |
|
|
|
* {@code ResolvableType.forClass(MyArrayList.class)}. |
|
|
|
* (including any generic parameters). |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
if (isArray()) { |
|
|
|
|
|
|
|
return getComponentType() + "[]"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (this.resolved == null) { |
|
|
|
|
|
|
|
return "?"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (this.type instanceof TypeVariable) { |
|
|
|
|
|
|
|
TypeVariable<?> variable = (TypeVariable<?>) this.type; |
|
|
|
|
|
|
|
if (this.variableResolver == null || this.variableResolver.resolveVariable(variable) == null) { |
|
|
|
|
|
|
|
// Don't bother with variable boundaries for toString()...
|
|
|
|
|
|
|
|
// Can cause infinite recursions in case of self-references
|
|
|
|
|
|
|
|
return "?"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
StringBuilder result = new StringBuilder(this.resolved.getName()); |
|
|
|
|
|
|
|
if (hasGenerics()) { |
|
|
|
|
|
|
|
result.append('<'); |
|
|
|
|
|
|
|
result.append(StringUtils.arrayToDelimitedString(getGenerics(), ", ")); |
|
|
|
|
|
|
|
result.append('>'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Factory methods
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class}, |
|
|
|
|
|
|
|
* using the full generic type information for assignability checks. |
|
|
|
|
|
|
|
* For example: {@code ResolvableType.forClass(MyArrayList.class)}. |
|
|
|
* @param sourceClass the source class (must not be {@code null} |
|
|
|
* @param sourceClass the source class (must not be {@code null} |
|
|
|
* @return a {@link ResolvableType} for the specified class
|
|
|
|
* @return a {@link ResolvableType} for the specified class
|
|
|
|
* @see #forClass(Class, Class) |
|
|
|
* @see #forClass(Class, Class) |
|
|
|
@ -872,9 +869,9 @@ public final class ResolvableType implements Serializable { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} with a given |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} |
|
|
|
* implementation. For example |
|
|
|
* with a given implementation. |
|
|
|
* {@code ResolvableType.forClass(List.class, MyArrayList.class)}. |
|
|
|
* For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}. |
|
|
|
* @param sourceClass the source class (must not be {@code null} |
|
|
|
* @param sourceClass the source class (must not be {@code null} |
|
|
|
* @param implementationClass the implementation class
|
|
|
|
* @param implementationClass the implementation class
|
|
|
|
* @return a {@link ResolvableType} for the specified class backed by the given |
|
|
|
* @return a {@link ResolvableType} for the specified class backed by the given |
|
|
|
@ -888,6 +885,38 @@ public final class ResolvableType implements Serializable { |
|
|
|
return (asType == NONE ? forType(sourceClass) : asType); |
|
|
|
return (asType == NONE ? forType(sourceClass) : asType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. |
|
|
|
|
|
|
|
* @param sourceClass the source class
|
|
|
|
|
|
|
|
* @param generics the generics of the class
|
|
|
|
|
|
|
|
* @return a {@link ResolvableType} for the specific class and generics |
|
|
|
|
|
|
|
* @see #forClassWithGenerics(Class, ResolvableType...) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) { |
|
|
|
|
|
|
|
Assert.notNull(sourceClass, "Source class must not be null"); |
|
|
|
|
|
|
|
Assert.notNull(generics, "Generics must not be null"); |
|
|
|
|
|
|
|
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length]; |
|
|
|
|
|
|
|
for (int i = 0; i < generics.length; i++) { |
|
|
|
|
|
|
|
resolvableGenerics[i] = forClass(generics[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return forClassWithGenerics(sourceClass, resolvableGenerics); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. |
|
|
|
|
|
|
|
* @param sourceClass the source class
|
|
|
|
|
|
|
|
* @param generics the generics of the class
|
|
|
|
|
|
|
|
* @return a {@link ResolvableType} for the specific class and generics |
|
|
|
|
|
|
|
* @see #forClassWithGenerics(Class, Class...) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) { |
|
|
|
|
|
|
|
Assert.notNull(sourceClass, "Source class must not be null"); |
|
|
|
|
|
|
|
Assert.notNull(generics, "Generics must not be null"); |
|
|
|
|
|
|
|
TypeVariable<?>[] variables = sourceClass.getTypeParameters(); |
|
|
|
|
|
|
|
Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified"); |
|
|
|
|
|
|
|
return forType(sourceClass, new TypeVariablesVariableResolver(variables, generics)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Field}. |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Field}. |
|
|
|
* @param field the source field |
|
|
|
* @param field the source field |
|
|
|
@ -1102,41 +1131,17 @@ public final class ResolvableType implements Serializable { |
|
|
|
* @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, "componentType 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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) { |
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. |
|
|
|
ResolvableType[] result = new ResolvableType[types.length]; |
|
|
|
* @param sourceClass the source class
|
|
|
|
for (int i = 0; i < types.length; i++) { |
|
|
|
* @param generics the generics of the class
|
|
|
|
result[i] = forType(types[i], owner); |
|
|
|
* @return a {@link ResolvableType} for the specific class and generics |
|
|
|
|
|
|
|
* @see #forClassWithGenerics(Class, ResolvableType...) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) { |
|
|
|
|
|
|
|
Assert.notNull(sourceClass, "Source class must not be null"); |
|
|
|
|
|
|
|
Assert.notNull(generics, "Generics must not be null"); |
|
|
|
|
|
|
|
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length]; |
|
|
|
|
|
|
|
for (int i = 0; i < generics.length; i++) { |
|
|
|
|
|
|
|
resolvableGenerics[i] = forClass(generics[i]); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return forClassWithGenerics(sourceClass, resolvableGenerics); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. |
|
|
|
|
|
|
|
* @param sourceClass the source class
|
|
|
|
|
|
|
|
* @param generics the generics of the class
|
|
|
|
|
|
|
|
* @return a {@link ResolvableType} for the specific class and generics |
|
|
|
|
|
|
|
* @see #forClassWithGenerics(Class, Class...) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) { |
|
|
|
|
|
|
|
Assert.notNull(sourceClass, "Source class must not be null"); |
|
|
|
|
|
|
|
Assert.notNull(generics, "Generics must not be null"); |
|
|
|
|
|
|
|
TypeVariable<?>[] variables = sourceClass.getTypeParameters(); |
|
|
|
|
|
|
|
Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified"); |
|
|
|
|
|
|
|
return forType(sourceClass, new TypeVariablesVariableResolver(variables, generics)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -1198,7 +1203,7 @@ public final class ResolvableType implements Serializable { |
|
|
|
|
|
|
|
|
|
|
|
// For simple Class references, build the wrapper right away -
|
|
|
|
// For simple Class references, build the wrapper right away -
|
|
|
|
// no expensive resolution necessary, so not worth caching...
|
|
|
|
// no expensive resolution necessary, so not worth caching...
|
|
|
|
if (type instanceof Class<?>) { |
|
|
|
if (type instanceof Class) { |
|
|
|
return new ResolvableType(type, typeProvider, variableResolver, null); |
|
|
|
return new ResolvableType(type, typeProvider, variableResolver, null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|