DATACMNS-1301 - SimpleTypeInformationMapper.resolveTypeFrom(…) now caches failed resolution attempts.
To prevent repeated failing calls to ClassUtils.forName(…) we now also cache the failed attempt and simply eagerly return null as subsequent similar attempts to resolve a class are going to fail anyway.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -32,7 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<String, ClassTypeInformation<?>> CACHE = new ConcurrentHashMap<String, ClassTypeInformation<?>>();
|
||||
private final Map<String, CachedTypeInformation> CACHE = new ConcurrentHashMap<String, CachedTypeInformation>();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
|
||||
@@ -55,23 +57,24 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassTypeInformation<?> information = CACHE.get(value);
|
||||
CachedTypeInformation cachedValue = CACHE.get(value);
|
||||
|
||||
if (information != null) {
|
||||
return information;
|
||||
if (cachedValue != null) {
|
||||
return cachedValue.getType();
|
||||
}
|
||||
|
||||
try {
|
||||
information = ClassTypeInformation.from(ClassUtils.forName(value, null));
|
||||
return cacheAndReturn(value, ClassTypeInformation.from(ClassUtils.forName(value, null)));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
return cacheAndReturn(value, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (information != null) {
|
||||
CACHE.put(value, information);
|
||||
}
|
||||
private ClassTypeInformation<?> cacheAndReturn(String value, ClassTypeInformation<?> type) {
|
||||
|
||||
return information;
|
||||
CACHE.put(value, CachedTypeInformation.of(type));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,4 +87,9 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
public String createAliasFor(TypeInformation<?> type) {
|
||||
return type.getType().getName();
|
||||
}
|
||||
|
||||
@Value(staticConstructor = "of")
|
||||
static class CachedTypeInformation {
|
||||
ClassTypeInformation<?> type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,13 @@ package org.springframework.data.convert;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.convert.SimpleTypeInformationMapper.CachedTypeInformation;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SimpleTypeInformationMapper}.
|
||||
@@ -71,4 +75,20 @@ public class SimpleTypeInformationMapperUnitTests {
|
||||
assertTrue(alias instanceof String);
|
||||
assertThat(alias, is((Object) String.class.getName()));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1301
|
||||
public void cachesFailedAttemptToLoadClass() {
|
||||
|
||||
TypeInformationMapper mapper = new SimpleTypeInformationMapper();
|
||||
|
||||
assertThat(mapper.resolveTypeFrom("foo"), is(nullValue()));
|
||||
|
||||
Map<String, CachedTypeInformation> cache = (Map<String, CachedTypeInformation>) ReflectionTestUtils.getField(mapper,
|
||||
"CACHE");
|
||||
|
||||
CachedTypeInformation value = cache.get("foo");
|
||||
|
||||
assertThat(value, is(notNullValue()));
|
||||
assertThat(value.getType(), is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user