DATACMNS-867 - Second draft.
This commit is contained in:
@@ -284,11 +284,8 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
|
||||
private ObjectInstantiatorClassGenerator() {
|
||||
|
||||
this.classLoader = AccessController.doPrivileged(new PrivilegedAction<ByteArrayClassLoader>() {
|
||||
public ByteArrayClassLoader run() {
|
||||
return new ByteArrayClassLoader(ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
});
|
||||
this.classLoader = AccessController.doPrivileged(
|
||||
(PrivilegedAction<ByteArrayClassLoader>) () -> new ByteArrayClassLoader(ClassUtils.getDefaultClassLoader()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.convert;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
@@ -34,7 +36,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ConfigurableTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<ClassTypeInformation<?>, Object> typeMap;
|
||||
private final Map<ClassTypeInformation<?>, Alias> typeToAlias;
|
||||
private final Map<Alias, ClassTypeInformation<?>> aliasToType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConfigurableTypeInformationMapper} for the given type map.
|
||||
@@ -44,18 +47,22 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
public ConfigurableTypeInformationMapper(Map<? extends Class<?>, String> sourceTypeMap) {
|
||||
|
||||
Assert.notNull(sourceTypeMap, "SourceTypeMap must not be null!");
|
||||
this.typeMap = new HashMap<ClassTypeInformation<?>, Object>(sourceTypeMap.size());
|
||||
|
||||
this.typeToAlias = new HashMap<>(sourceTypeMap.size());
|
||||
this.aliasToType = new HashMap<>(sourceTypeMap.size());
|
||||
|
||||
for (Entry<? extends Class<?>, String> entry : sourceTypeMap.entrySet()) {
|
||||
ClassTypeInformation<?> key = ClassTypeInformation.from(entry.getKey());
|
||||
String value = entry.getValue();
|
||||
|
||||
if (typeMap.containsValue(value)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Detected mapping ambiguity! String %s cannot be mapped to more than one type!", value));
|
||||
ClassTypeInformation<?> type = ClassTypeInformation.from(entry.getKey());
|
||||
Alias alias = Alias.of(entry.getValue());
|
||||
|
||||
if (typeToAlias.containsValue(alias)) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Detected mapping ambiguity! String %s cannot be mapped to more than one type!", alias));
|
||||
}
|
||||
|
||||
this.typeMap.put(key, value);
|
||||
this.typeToAlias.put(type, alias);
|
||||
this.aliasToType.put(alias, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,26 +70,16 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Object createAliasFor(TypeInformation<?> type) {
|
||||
return typeMap.get(type);
|
||||
public Alias createAliasFor(TypeInformation<?> type) {
|
||||
return typeToAlias.getOrDefault(type, Alias.NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.lang.Object)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(org.springframework.data.mapping.Alias)
|
||||
*/
|
||||
public ClassTypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Entry<ClassTypeInformation<?>, Object> entry : typeMap.entrySet()) {
|
||||
if (entry.getValue().equals(alias)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
return Optional.ofNullable(aliasToType.get(alias));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,14 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -41,7 +44,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
private final TypeAliasAccessor<S> accessor;
|
||||
private final List<? extends TypeInformationMapper> mappers;
|
||||
private final Map<Object, TypeInformation<?>> typeCache;
|
||||
private final Map<Alias, Optional<TypeInformation<?>>> typeCache;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}. It will use a
|
||||
@@ -80,7 +83,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
Assert.notNull(accessor, "Accessor must not be null!");
|
||||
Assert.notNull(additionalMappers, "AdditionalMappers must not be null!");
|
||||
|
||||
List<TypeInformationMapper> mappers = new ArrayList<TypeInformationMapper>(additionalMappers.size() + 1);
|
||||
List<TypeInformationMapper> mappers = new ArrayList<>(additionalMappers.size() + 1);
|
||||
if (mappingContext != null) {
|
||||
mappers.add(new MappingContextTypeInformationMapper(mappingContext));
|
||||
}
|
||||
@@ -88,19 +91,18 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
this.mappers = Collections.unmodifiableList(mappers);
|
||||
this.accessor = accessor;
|
||||
this.typeCache = new ConcurrentHashMap<Object, TypeInformation<?>>();
|
||||
this.typeCache = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object)
|
||||
*/
|
||||
public TypeInformation<?> readType(S source) {
|
||||
public Optional<TypeInformation<?>> readType(S source) {
|
||||
|
||||
Assert.notNull(source, "Source object must not be null!");
|
||||
|
||||
Object alias = accessor.readAliasFrom(source);
|
||||
return alias == null ? null : getFromCacheOrCreate(alias);
|
||||
return getFromCacheOrCreate(accessor.readAliasFrom(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,53 +112,41 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param alias
|
||||
* @return
|
||||
*/
|
||||
private TypeInformation<?> getFromCacheOrCreate(Object alias) {
|
||||
|
||||
TypeInformation<?> typeInformation = typeCache.get(alias);
|
||||
|
||||
if (typeInformation != null) {
|
||||
return typeInformation;
|
||||
}
|
||||
|
||||
for (TypeInformationMapper mapper : mappers) {
|
||||
|
||||
typeInformation = mapper.resolveTypeFrom(alias);
|
||||
|
||||
if (typeInformation != null) {
|
||||
typeCache.put(alias, typeInformation);
|
||||
return typeInformation;
|
||||
}
|
||||
}
|
||||
|
||||
return typeInformation;
|
||||
private Optional<TypeInformation<?>> getFromCacheOrCreate(Alias alias) {
|
||||
return typeCache.computeIfAbsent(alias, key -> Optionals.firstNonEmpty(mappers, it -> it.resolveTypeFrom(alias)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object, org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeInformation<? extends T> readType(S source, TypeInformation<T> basicType) {
|
||||
|
||||
Assert.notNull(source, "Source object must not be null!");
|
||||
Class<?> documentsTargetType = getDefaultedTypeToBeUsed(source);
|
||||
Assert.notNull(source, "Source must not be null!");
|
||||
Assert.notNull(basicType, "Basic type must not be null!");
|
||||
|
||||
if (documentsTargetType == null) {
|
||||
return basicType;
|
||||
}
|
||||
Optional<TypeInformation<? extends T>> calculated = getDefaultedTypeToBeUsed(source)//
|
||||
.map(it -> foo(it, basicType));
|
||||
|
||||
Class<T> rawType = basicType == null ? null : basicType.getType();
|
||||
return calculated.orElse(basicType);
|
||||
}
|
||||
|
||||
boolean isMoreConcreteCustomType = rawType == null ? true
|
||||
: rawType.isAssignableFrom(documentsTargetType) && !rawType.equals(documentsTargetType);
|
||||
// @SuppressWarnings("unchecked")
|
||||
private static <T> TypeInformation<? extends T> foo(Class<?> sourceType, TypeInformation<T> type) {
|
||||
|
||||
if (!isMoreConcreteCustomType) {
|
||||
return basicType;
|
||||
}
|
||||
return specializeOrDefault(sourceType, type);
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(documentsTargetType);
|
||||
// return type//
|
||||
// .<TypeInformation<? extends T>>map(it -> specializeOrDefault(sourceType, it))
|
||||
// .orElseGet(() -> (TypeInformation<? extends T>) ClassTypeInformation.from(sourceType));
|
||||
}
|
||||
|
||||
return (TypeInformation<? extends T>) (basicType != null ? basicType.specialize(targetType) : targetType);
|
||||
private static <T> TypeInformation<? extends T> specializeOrDefault(Class<?> it, TypeInformation<T> type) {
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(it);
|
||||
Class<T> rawType = type.getType();
|
||||
|
||||
return rawType.isAssignableFrom(it) && !rawType.equals(it) ? type.specialize(targetType) : type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,12 +156,9 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getDefaultedTypeToBeUsed(S source) {
|
||||
|
||||
TypeInformation<?> documentsTargetTypeInformation = readType(source);
|
||||
documentsTargetTypeInformation = documentsTargetTypeInformation == null ? getFallbackTypeFor(source)
|
||||
: documentsTargetTypeInformation;
|
||||
return documentsTargetTypeInformation == null ? null : documentsTargetTypeInformation.getType();
|
||||
private Optional<Class<?>> getDefaultedTypeToBeUsed(S source) {
|
||||
return readType(source).map(it -> readType(source)).orElseGet(() -> getFallbackTypeFor(source))
|
||||
.map(it -> it.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,8 +167,8 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param source will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected TypeInformation<?> getFallbackTypeFor(S source) {
|
||||
return null;
|
||||
protected Optional<TypeInformation<?>> getFallbackTypeFor(S source) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -200,10 +187,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
Assert.notNull(info, "TypeInformation must not be null!");
|
||||
|
||||
Object alias = getAliasFor(info);
|
||||
if (alias != null) {
|
||||
accessor.writeTypeTo(sink, alias);
|
||||
}
|
||||
getAliasFor(info).getValue().ifPresent(it -> accessor.writeTypeTo(sink, it));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,17 +197,10 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @return the alias for the given {@link TypeInformation} or {@literal null} of none was found or all mappers
|
||||
* returned {@literal null}.
|
||||
*/
|
||||
protected final Object getAliasFor(TypeInformation<?> info) {
|
||||
protected final Alias getAliasFor(TypeInformation<?> info) {
|
||||
|
||||
Assert.notNull(info, "TypeInformation must not be null!");
|
||||
|
||||
for (TypeInformationMapper mapper : mappers) {
|
||||
Object alias = mapper.createAliasFor(info);
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return Optionals.firstNonEmpty(mappers, it -> it.createAliasFor(info), Alias.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@ package org.springframework.data.convert;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.CacheValue;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -35,7 +36,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class MappingContextTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
private final Map<ClassTypeInformation<?>, CacheValue<Object>> typeMap;
|
||||
private final Map<ClassTypeInformation<?>, Alias> typeMap;
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext;
|
||||
|
||||
/**
|
||||
@@ -48,11 +49,11 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
|
||||
this.typeMap = new ConcurrentHashMap<ClassTypeInformation<?>, CacheValue<Object>>();
|
||||
this.typeMap = new ConcurrentHashMap<>();
|
||||
this.mappingContext = mappingContext;
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
safelyAddToCache(entity.getTypeInformation().getRawTypeInformation(), entity.getTypeAlias());
|
||||
verify(entity.getTypeInformation().getRawTypeInformation(), entity.getTypeAlias());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,24 +61,11 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Object createAliasFor(TypeInformation<?> type) {
|
||||
public Alias createAliasFor(TypeInformation<?> type) {
|
||||
|
||||
CacheValue<Object> key = typeMap.get(type);
|
||||
|
||||
if (key != null) {
|
||||
return key.getValue();
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> entity = mappingContext.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object alias = entity.getTypeAlias();
|
||||
safelyAddToCache(type.getRawTypeInformation(), alias);
|
||||
|
||||
return alias;
|
||||
return typeMap.computeIfAbsent(type.getRawTypeInformation(), key -> {
|
||||
return verify(key, mappingContext.getPersistentEntity(key).map(it -> it.getTypeAlias()).orElse(Alias.NONE));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,73 +74,59 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
* @param key must not be {@literal null}.
|
||||
* @param alias can be {@literal null}.
|
||||
*/
|
||||
private void safelyAddToCache(ClassTypeInformation<?> key, Object alias) {
|
||||
|
||||
CacheValue<Object> aliasToBeCached = CacheValue.ofNullable(alias);
|
||||
|
||||
if (alias == null && !typeMap.containsKey(key)) {
|
||||
typeMap.put(key, aliasToBeCached);
|
||||
return;
|
||||
}
|
||||
|
||||
CacheValue<Object> alreadyCachedAlias = typeMap.get(key);
|
||||
private Alias verify(ClassTypeInformation<?> key, Alias alias) {
|
||||
|
||||
// Reject second alias for same type
|
||||
|
||||
if (alreadyCachedAlias != null && alreadyCachedAlias.isPresent() && !alreadyCachedAlias.hasValue(alias)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Trying to register alias '%s', but found already registered alias '%s' for type %s!", alias,
|
||||
alreadyCachedAlias, key));
|
||||
Alias existingAlias = typeMap.getOrDefault(key, Alias.NONE);
|
||||
|
||||
if (existingAlias.isPresentButDifferent(alias)) {
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Trying to register alias '%s', but found already registered alias '%s' for type %s!", alias,
|
||||
existingAlias, key));
|
||||
}
|
||||
|
||||
// Reject second type for same alias
|
||||
|
||||
if (typeMap.containsValue(aliasToBeCached)) {
|
||||
if (typeMap.containsValue(alias)) {
|
||||
|
||||
for (Entry<ClassTypeInformation<?>, CacheValue<Object>> entry : typeMap.entrySet()) {
|
||||
typeMap.entrySet().stream()//
|
||||
.filter(it -> it.getValue().hasSamePresentValueAs(alias) && !it.getKey().equals(key))//
|
||||
.findFirst().ifPresent(it -> {
|
||||
|
||||
CacheValue<Object> value = entry.getValue();
|
||||
|
||||
if (!value.isPresent()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value.hasValue(alias) && !entry.getKey().equals(key)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Detected existing type mapping of %s to alias '%s' but attempted to bind the same alias to %s!", key,
|
||||
alias, entry.getKey()));
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Detected existing type mapping of %s to alias '%s' but attempted to bind the same alias to %s!", key,
|
||||
alias, it.getKey()));
|
||||
});
|
||||
}
|
||||
|
||||
typeMap.put(key, aliasToBeCached);
|
||||
return alias;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.lang.Object)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.util.Optional)
|
||||
*/
|
||||
public ClassTypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
|
||||
return alias.getValue().map(it -> {
|
||||
|
||||
for (Entry<ClassTypeInformation<?>, Alias> entry : typeMap.entrySet()) {
|
||||
if (entry.getValue().hasValue(it)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
|
||||
if (entity.getTypeAlias().hasValue(it)) {
|
||||
return entity.getTypeInformation().getRawTypeInformation();
|
||||
}
|
||||
}
|
||||
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Entry<ClassTypeInformation<?>, CacheValue<Object>> entry : typeMap.entrySet()) {
|
||||
|
||||
CacheValue<Object> cachedAlias = entry.getValue();
|
||||
|
||||
if (cachedAlias.hasValue(alias)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
if (alias.equals(entity.getTypeAlias())) {
|
||||
return entity.getTypeInformation().getRawTypeInformation();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
.map(it -> constructor.getParameters().stream()//
|
||||
.map(parameter -> it.getParameterValue(parameter).orElse(null))//
|
||||
.collect(Collectors.toList()))//
|
||||
.orElse(Collections.emptyList());
|
||||
.orElseGet(() -> Collections.emptyList());
|
||||
|
||||
try {
|
||||
return (T) BeanUtils.instantiateClass(constructor.getConstructor(), params.toArray());
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Basic {@link TypeInformationMapper} implementation that interprets the alias handles as fully qualified class name
|
||||
@@ -32,7 +33,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, Optional<ClassTypeInformation<?>>> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
|
||||
@@ -43,35 +44,11 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
* @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the
|
||||
* class cannot be loaded.
|
||||
*/
|
||||
public ClassTypeInformation<?> resolveTypeFrom(Object alias) {
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
|
||||
if (!(alias instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String value = (String) alias;
|
||||
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassTypeInformation<?> information = CACHE.get(value);
|
||||
|
||||
if (information != null) {
|
||||
return information;
|
||||
}
|
||||
|
||||
try {
|
||||
information = ClassTypeInformation.from(ClassUtils.forName(value, null));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (information != null) {
|
||||
CACHE.put(value, information);
|
||||
}
|
||||
|
||||
return information;
|
||||
return alias.mapTyped(String.class)//
|
||||
.flatMap(it -> CACHE.computeIfAbsent(it, SimpleTypeInformationMapper::loadClass).map(type -> type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +58,16 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @return the String representation to be stored or {@literal null} if no type information shall be stored.
|
||||
*/
|
||||
public String createAliasFor(TypeInformation<?> type) {
|
||||
return type.getType().getName();
|
||||
public Alias createAliasFor(TypeInformation<?> type) {
|
||||
return Alias.of(type.getType().getName());
|
||||
}
|
||||
|
||||
private static Optional<ClassTypeInformation<?>> loadClass(String typeName) {
|
||||
|
||||
try {
|
||||
return Optional.of(ClassTypeInformation.from(ClassUtils.forName(typeName, null)));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
|
||||
/**
|
||||
* Interface to abstract implementations of how to access a type alias from a given source or sink.
|
||||
*
|
||||
@@ -28,7 +30,7 @@ public interface TypeAliasAccessor<S> {
|
||||
* @param source
|
||||
* @return can be {@literal null} in case no alias was found.
|
||||
*/
|
||||
Object readAliasFrom(S source);
|
||||
Alias readAliasFrom(S source);
|
||||
|
||||
/**
|
||||
* Writes the given type alias to the given sink.
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
@@ -30,7 +33,7 @@ public interface TypeInformationMapper {
|
||||
* @param alias can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> resolveTypeFrom(Object alias);
|
||||
Optional<TypeInformation<?>> resolveTypeFrom(Alias alias);
|
||||
|
||||
/**
|
||||
* Returns the alias to be used for the given {@link TypeInformation}.
|
||||
@@ -38,5 +41,5 @@ public interface TypeInformationMapper {
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
Object createAliasFor(TypeInformation<?> type);
|
||||
Alias createAliasFor(TypeInformation<?> type);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
@@ -30,7 +32,7 @@ public interface TypeMapper<S> {
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> readType(S source);
|
||||
Optional<TypeInformation<?>> readType(S source);
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} from the given source if it is a more concrete type than the given default one.
|
||||
|
||||
Reference in New Issue
Block a user