Skip to content

Commit 4c74148

Browse files
committed
ResolvableType returns clone for cached state with original local source
Issue: SPR-16210
1 parent 357fb48 commit 4c74148

File tree

2 files changed

+44
-35
lines changed

2 files changed

+44
-35
lines changed

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

+41-34
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -117,36 +117,35 @@ public class ResolvableType implements Serializable {
117117
@Nullable
118118
private final ResolvableType componentType;
119119

120-
/**
121-
* Copy of the resolved value.
122-
*/
123120
@Nullable
124-
private final Class<?> resolved;
121+
private final Integer hash;
125122

126123
@Nullable
127-
private final Integer hash;
124+
private Class<?> resolved;
128125

129126
@Nullable
130-
private ResolvableType superType;
127+
private volatile ResolvableType superType;
131128

132129
@Nullable
133-
private ResolvableType[] interfaces;
130+
private volatile ResolvableType[] interfaces;
134131

135132
@Nullable
136-
private ResolvableType[] generics;
133+
private volatile ResolvableType[] generics;
137134

138135

139136
/**
140137
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
141138
* with no upfront resolution.
142139
*/
143-
private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
140+
private ResolvableType(
141+
Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
142+
144143
this.type = type;
145144
this.typeProvider = typeProvider;
146145
this.variableResolver = variableResolver;
147146
this.componentType = null;
148-
this.resolved = null;
149147
this.hash = calculateHashCode();
148+
this.resolved = null;
150149
}
151150

152151
/**
@@ -161,8 +160,8 @@ private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
161160
this.typeProvider = typeProvider;
162161
this.variableResolver = variableResolver;
163162
this.componentType = null;
164-
this.resolved = resolveClass();
165163
this.hash = hash;
164+
this.resolved = resolveClass();
166165
}
167166

168167
/**
@@ -176,8 +175,8 @@ private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
176175
this.typeProvider = typeProvider;
177176
this.variableResolver = variableResolver;
178177
this.componentType = componentType;
179-
this.resolved = resolveClass();
180178
this.hash = null;
179+
this.resolved = resolveClass();
181180
}
182181

183182
/**
@@ -453,10 +452,12 @@ public ResolvableType getSuperType() {
453452
if (resolved == null || resolved.getGenericSuperclass() == null) {
454453
return NONE;
455454
}
456-
if (this.superType == null) {
457-
this.superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
455+
ResolvableType superType = this.superType;
456+
if (superType == null) {
457+
superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
458+
this.superType = superType;
458459
}
459-
return this.superType;
460+
return superType;
460461
}
461462

462463
/**
@@ -470,10 +471,12 @@ public ResolvableType[] getInterfaces() {
470471
if (resolved == null || ObjectUtils.isEmpty(resolved.getGenericInterfaces())) {
471472
return EMPTY_TYPES_ARRAY;
472473
}
473-
if (this.interfaces == null) {
474-
this.interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
474+
ResolvableType[] interfaces = this.interfaces;
475+
if (interfaces == null) {
476+
interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
477+
this.interfaces = interfaces;
475478
}
476-
return this.interfaces;
479+
return interfaces;
477480
}
478481

479482
/**
@@ -667,24 +670,25 @@ public ResolvableType[] getGenerics() {
667670
if (this == NONE) {
668671
return EMPTY_TYPES_ARRAY;
669672
}
670-
if (this.generics == null) {
673+
ResolvableType[] generics = this.generics;
674+
if (generics == null) {
671675
if (this.type instanceof Class) {
672676
Class<?> typeClass = (Class<?>) this.type;
673-
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
677+
generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
674678
}
675679
else if (this.type instanceof ParameterizedType) {
676680
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
677-
ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
681+
generics = new ResolvableType[actualTypeArguments.length];
678682
for (int i = 0; i < actualTypeArguments.length; i++) {
679683
generics[i] = forType(actualTypeArguments[i], this.variableResolver);
680684
}
681-
this.generics = generics;
682685
}
683686
else {
684-
this.generics = resolveType().getGenerics();
687+
generics = resolveType().getGenerics();
685688
}
689+
this.generics = generics;
686690
}
687-
return this.generics;
691+
return generics;
688692
}
689693

690694
/**
@@ -748,7 +752,7 @@ public Class<?> resolveGeneric(int... indexes) {
748752
*/
749753
@Nullable
750754
public Class<?> resolve() {
751-
return (this.resolved != null ? this.resolved : null);
755+
return this.resolved;
752756
}
753757

754758
/**
@@ -1372,7 +1376,9 @@ static ResolvableType forType(@Nullable Type type, @Nullable VariableResolver va
13721376
* @param variableResolver the variable resolver or {@code null}
13731377
* @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
13741378
*/
1375-
static ResolvableType forType(@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
1379+
static ResolvableType forType(
1380+
@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
1381+
13761382
if (type == null && typeProvider != null) {
13771383
type = SerializableTypeWrapper.forTypeProvider(typeProvider);
13781384
}
@@ -1390,13 +1396,14 @@ static ResolvableType forType(@Nullable Type type, @Nullable TypeProvider typePr
13901396
cache.purgeUnreferencedEntries();
13911397

13921398
// Check the cache - we may have a ResolvableType which has been resolved before...
1393-
ResolvableType key = new ResolvableType(type, typeProvider, variableResolver);
1394-
ResolvableType resolvableType = cache.get(key);
1395-
if (resolvableType == null) {
1396-
resolvableType = new ResolvableType(type, typeProvider, variableResolver, key.hash);
1397-
cache.put(resolvableType, resolvableType);
1398-
}
1399-
return resolvableType;
1399+
ResolvableType resultType = new ResolvableType(type, typeProvider, variableResolver);
1400+
ResolvableType cachedType = cache.get(resultType);
1401+
if (cachedType == null) {
1402+
cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash);
1403+
cache.put(cachedType, cachedType);
1404+
}
1405+
resultType.resolved = cachedType.resolved;
1406+
return resultType;
14001407
}
14011408

14021409
/**

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -176,11 +176,13 @@ public void forPrivateField() throws Exception {
176176
ResolvableType type = ResolvableType.forField(field);
177177
assertThat(type.getType(), equalTo(field.getGenericType()));
178178
assertThat(type.resolve(), equalTo((Class) List.class));
179+
assertThat(type.getSource(), sameInstance(field));
179180

180181
Field field2 = Fields.class.getDeclaredField("otherPrivateField");
181182
ResolvableType type2 = ResolvableType.forField(field2);
182183
assertThat(type2.getType(), equalTo(field2.getGenericType()));
183184
assertThat(type2.resolve(), equalTo((Class) List.class));
185+
assertThat(type2.getSource(), sameInstance(field2));
184186

185187
assertEquals(type, type2);
186188
assertEquals(type.hashCode(), type2.hashCode());

0 commit comments

Comments
 (0)