Browse Source

ResolvableType returns clone for cached state with original local source

Issue: SPR-16210
pull/1647/head
Juergen Hoeller 8 years ago
parent
commit
4c7414833b
  1. 75
      spring-core/src/main/java/org/springframework/core/ResolvableType.java
  2. 4
      spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@ -117,36 +117,35 @@ public class ResolvableType implements Serializable { @@ -117,36 +117,35 @@ public class ResolvableType implements Serializable {
@Nullable
private final ResolvableType componentType;
/**
* Copy of the resolved value.
*/
@Nullable
private final Class<?> resolved;
private final Integer hash;
@Nullable
private final Integer hash;
private Class<?> resolved;
@Nullable
private ResolvableType superType;
private volatile ResolvableType superType;
@Nullable
private ResolvableType[] interfaces;
private volatile ResolvableType[] interfaces;
@Nullable
private ResolvableType[] generics;
private volatile ResolvableType[] generics;
/**
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
* with no upfront resolution.
*/
private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
private ResolvableType(
Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
this.componentType = null;
this.resolved = null;
this.hash = calculateHashCode();
this.resolved = null;
}
/**
@ -161,8 +160,8 @@ public class ResolvableType implements Serializable { @@ -161,8 +160,8 @@ public class ResolvableType implements Serializable {
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
this.componentType = null;
this.resolved = resolveClass();
this.hash = hash;
this.resolved = resolveClass();
}
/**
@ -176,8 +175,8 @@ public class ResolvableType implements Serializable { @@ -176,8 +175,8 @@ public class ResolvableType implements Serializable {
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
this.componentType = componentType;
this.resolved = resolveClass();
this.hash = null;
this.resolved = resolveClass();
}
/**
@ -453,10 +452,12 @@ public class ResolvableType implements Serializable { @@ -453,10 +452,12 @@ public class ResolvableType implements Serializable {
if (resolved == null || resolved.getGenericSuperclass() == null) {
return NONE;
}
if (this.superType == null) {
this.superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
ResolvableType superType = this.superType;
if (superType == null) {
superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
this.superType = superType;
}
return this.superType;
return superType;
}
/**
@ -470,10 +471,12 @@ public class ResolvableType implements Serializable { @@ -470,10 +471,12 @@ public class ResolvableType implements Serializable {
if (resolved == null || ObjectUtils.isEmpty(resolved.getGenericInterfaces())) {
return EMPTY_TYPES_ARRAY;
}
if (this.interfaces == null) {
this.interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
ResolvableType[] interfaces = this.interfaces;
if (interfaces == null) {
interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
this.interfaces = interfaces;
}
return this.interfaces;
return interfaces;
}
/**
@ -667,24 +670,25 @@ public class ResolvableType implements Serializable { @@ -667,24 +670,25 @@ public class ResolvableType implements Serializable {
if (this == NONE) {
return EMPTY_TYPES_ARRAY;
}
if (this.generics == null) {
ResolvableType[] generics = this.generics;
if (generics == null) {
if (this.type instanceof Class) {
Class<?> typeClass = (Class<?>) this.type;
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
}
else if (this.type instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
generics = new ResolvableType[actualTypeArguments.length];
for (int i = 0; i < actualTypeArguments.length; i++) {
generics[i] = forType(actualTypeArguments[i], this.variableResolver);
}
this.generics = generics;
}
else {
this.generics = resolveType().getGenerics();
generics = resolveType().getGenerics();
}
this.generics = generics;
}
return this.generics;
return generics;
}
/**
@ -748,7 +752,7 @@ public class ResolvableType implements Serializable { @@ -748,7 +752,7 @@ public class ResolvableType implements Serializable {
*/
@Nullable
public Class<?> resolve() {
return (this.resolved != null ? this.resolved : null);
return this.resolved;
}
/**
@ -1372,7 +1376,9 @@ public class ResolvableType implements Serializable { @@ -1372,7 +1376,9 @@ public class ResolvableType implements Serializable {
* @param variableResolver the variable resolver or {@code null}
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
*/
static ResolvableType forType(@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
static ResolvableType forType(
@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
if (type == null && typeProvider != null) {
type = SerializableTypeWrapper.forTypeProvider(typeProvider);
}
@ -1390,13 +1396,14 @@ public class ResolvableType implements Serializable { @@ -1390,13 +1396,14 @@ public class ResolvableType implements Serializable {
cache.purgeUnreferencedEntries();
// Check the cache - we may have a ResolvableType which has been resolved before...
ResolvableType key = new ResolvableType(type, typeProvider, variableResolver);
ResolvableType resolvableType = cache.get(key);
if (resolvableType == null) {
resolvableType = new ResolvableType(type, typeProvider, variableResolver, key.hash);
cache.put(resolvableType, resolvableType);
}
return resolvableType;
ResolvableType resultType = new ResolvableType(type, typeProvider, variableResolver);
ResolvableType cachedType = cache.get(resultType);
if (cachedType == null) {
cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash);
cache.put(cachedType, cachedType);
}
resultType.resolved = cachedType.resolved;
return resultType;
}
/**

4
spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@ -176,11 +176,13 @@ public class ResolvableTypeTests { @@ -176,11 +176,13 @@ public class ResolvableTypeTests {
ResolvableType type = ResolvableType.forField(field);
assertThat(type.getType(), equalTo(field.getGenericType()));
assertThat(type.resolve(), equalTo((Class) List.class));
assertThat(type.getSource(), sameInstance(field));
Field field2 = Fields.class.getDeclaredField("otherPrivateField");
ResolvableType type2 = ResolvableType.forField(field2);
assertThat(type2.getType(), equalTo(field2.getGenericType()));
assertThat(type2.resolve(), equalTo((Class) List.class));
assertThat(type2.getSource(), sameInstance(field2));
assertEquals(type, type2);
assertEquals(type.hashCode(), type2.hashCode());

Loading…
Cancel
Save