Browse Source

Prevented potential infinite recursion in hashCode/equals

Issue: SPR-11219
pull/292/merge
Juergen Hoeller 11 years ago
parent
commit
994efe45fd
  1. 65
      spring-core/src/main/java/org/springframework/core/ResolvableType.java

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

@ -73,11 +73,9 @@ import org.springframework.util.StringUtils; @@ -73,11 +73,9 @@ import org.springframework.util.StringUtils;
* @see #forClass(Class)
* @see #forType(Type)
*/
@SuppressWarnings("serial")
public final class ResolvableType implements Serializable {
private static final long serialVersionUID = 1L;
private static ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
new ConcurrentReferenceHashMap<ResolvableType, ResolvableType>();
@ -93,14 +91,14 @@ public final class ResolvableType implements Serializable { @@ -93,14 +91,14 @@ public final class ResolvableType implements Serializable {
/**
* The underlying java type being managed (only ever {@code null} for {@link #NONE}).
* The underlying Java type being managed (only ever {@code null} for {@link #NONE}).
*/
private final Type type;
/**
* Optional provider for the type.
*/
private TypeProvider typeProvider;
private final TypeProvider typeProvider;
/**
* The {@code VariableResolver} to use or {@code null} if no resolver is available.
@ -125,12 +123,13 @@ public final class ResolvableType implements Serializable { @@ -125,12 +123,13 @@ public final class ResolvableType implements Serializable {
/**
* Private constructor used to create a new {@link ResolvableType}.
* @param type the underlying java type (may only be {@code null} for {@link #NONE})
* @param type the underlying Java type (may only be {@code null} for {@link #NONE})
* @param variableResolver the resolver used for {@link TypeVariable}s (may be {@code null})
* @param componentType an option declared component type for arrays (may be {@code null})
*/
private ResolvableType(Type type, TypeProvider typeProvider,
VariableResolver variableResolver, ResolvableType componentType) {
private ResolvableType(
Type type, TypeProvider typeProvider, VariableResolver variableResolver, ResolvableType componentType) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
@ -590,7 +589,6 @@ public final class ResolvableType implements Serializable { @@ -590,7 +589,6 @@ public final class ResolvableType implements Serializable {
if (this.type instanceof ParameterizedType) {
return forType(((ParameterizedType) this.type).getRawType(), this.variableResolver);
}
if (this.type instanceof WildcardType) {
Type resolved = resolveBounds(((WildcardType) this.type).getUpperBounds());
if (resolved == null) {
@ -598,10 +596,8 @@ public final class ResolvableType implements Serializable { @@ -598,10 +596,8 @@ public final class ResolvableType implements Serializable {
}
return forType(resolved, this.variableResolver);
}
if (this.type instanceof TypeVariable) {
TypeVariable<?> variable = (TypeVariable<?>) this.type;
// Try default variable resolution
if (this.variableResolver != null) {
ResolvableType resolved = this.variableResolver.resolveVariable(variable);
@ -609,11 +605,9 @@ public final class ResolvableType implements Serializable { @@ -609,11 +605,9 @@ public final class ResolvableType implements Serializable {
return resolved;
}
}
// Fallback to bounds
return forType(resolveBounds(variable.getBounds()), this.variableResolver);
}
return NONE;
}
@ -628,7 +622,6 @@ public final class ResolvableType implements Serializable { @@ -628,7 +622,6 @@ public final class ResolvableType implements Serializable {
if (this.type instanceof TypeVariable) {
return resolveType().resolveVariable(variable);
}
if (this.type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) this.type;
TypeVariable<?>[] variables = resolve().getTypeParameters();
@ -638,16 +631,13 @@ public final class ResolvableType implements Serializable { @@ -638,16 +631,13 @@ public final class ResolvableType implements Serializable {
return forType(actualType, this.variableResolver);
}
}
if (parameterizedType.getOwnerType() != null) {
return forType(parameterizedType.getOwnerType(), this.variableResolver).resolveVariable(variable);
}
}
if (this.variableResolver != null) {
return this.variableResolver.resolveVariable(variable);
}
return null;
}
@ -673,27 +663,22 @@ public final class ResolvableType implements Serializable { @@ -673,27 +663,22 @@ public final class ResolvableType implements Serializable {
@Override
public boolean equals(Object obj) {
if (obj == this) {
if (this == obj) {
return true;
}
if (obj instanceof ResolvableType) {
ResolvableType other = (ResolvableType) obj;
boolean equals = ObjectUtils.nullSafeEquals(this.type, other.type);
equals &= ObjectUtils.nullSafeEquals(getSource(), other.getSource());
equals &= variableResolverSourceEquals(this.variableResolver, other.variableResolver);
equals &= ObjectUtils.nullSafeEquals(this.componentType, other.componentType);
return equals;
if (!(obj instanceof ResolvableType)) {
return false;
}
return false;
ResolvableType other = (ResolvableType) obj;
return (ObjectUtils.nullSafeEquals(this.type, other.type) &&
ObjectUtils.nullSafeEquals(getSource(), other.getSource()) &&
variableResolverSourceEquals(other.variableResolver) &&
ObjectUtils.nullSafeEquals(this.componentType, other.componentType));
}
@Override
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(this.type);
hashCode = hashCode * 31 + ObjectUtils.nullSafeHashCode(
this.variableResolver == null ? null : this.variableResolver.getSource());
hashCode = hashCode * 31 + ObjectUtils.nullSafeHashCode(this.componentType);
return hashCode;
return ObjectUtils.nullSafeHashCode(this.type);
}
/**
@ -713,10 +698,15 @@ public final class ResolvableType implements Serializable { @@ -713,10 +698,15 @@ public final class ResolvableType implements Serializable {
return new DefaultVariableResolver();
}
private static boolean variableResolverSourceEquals(VariableResolver o1, VariableResolver o2) {
Object s1 = (o1 == null ? null : o1.getSource());
Object s2 = (o2 == null ? null : o2.getSource());
return ObjectUtils.nullSafeEquals(s1,s2);
private boolean variableResolverSourceEquals(VariableResolver other) {
if (this.variableResolver == null) {
return (other == null);
}
if (other == null) {
return false;
}
Object src = this.variableResolver.getSource();
return (src == this ? src == other.getSource() : ObjectUtils.nullSafeEquals(src, other.getSource()));
}
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
@ -840,6 +830,7 @@ public final class ResolvableType implements Serializable { @@ -840,6 +830,7 @@ public final class ResolvableType implements Serializable {
*/
public static ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex,
Class<?> implementationClass) {
Assert.notNull(constructor, "Constructor must not be null");
MethodParameter methodParameter = new MethodParameter(constructor, parameterIndex);
methodParameter.setContainingClass(implementationClass);
@ -923,7 +914,7 @@ public final class ResolvableType implements Serializable { @@ -923,7 +914,7 @@ public final class ResolvableType implements Serializable {
* @param componentType the component type
* @return a {@link ResolvableType} as an array of the specified component type
*/
public static ResolvableType forArrayComponent(final ResolvableType componentType) {
public static ResolvableType forArrayComponent(ResolvableType componentType) {
Assert.notNull(componentType, "ComponentType must not be null");
Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
return new ResolvableType(arrayClass, null, null, componentType);
@ -1035,7 +1026,7 @@ public final class ResolvableType implements Serializable { @@ -1035,7 +1026,7 @@ public final class ResolvableType implements Serializable {
Object getSource();
/**
* Resolve the specified varaible.
* Resolve the specified variable.
* @param variable the variable to resolve
* @return the resolved variable or {@code null}
*/

Loading…
Cancel
Save