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:
Oliver Gierke
2018-04-18 11:54:37 +02:00
parent 1001f4e71f
commit 8d99e0d83d
2 changed files with 38 additions and 10 deletions

View File

@@ -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;
}
}

View File

@@ -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()));
}
}