DATACMNS-1101 - Remove Optional from mapping/convert use except for caching of absence and computations that are used to populate caches.
This commit is contained in:
committed by
Oliver Gierke
parent
74fbe13f54
commit
6c65c02e78
@@ -21,10 +21,11 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.asm.Type;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.MappingInstantiationException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -139,15 +141,17 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
return true;
|
||||
}
|
||||
|
||||
return entity.getPersistenceConstructor()//
|
||||
.map(PreferredConstructor::getConstructor)//
|
||||
.map(Constructor::getModifiers)//
|
||||
.map(modifier -> !Modifier.isPublic(modifier)).orElse(false);
|
||||
PreferredConstructor<?, ?> persistenceConstructor = entity.getPersistenceConstructor();
|
||||
if (persistenceConstructor == null || !Modifier.isPublic(persistenceConstructor.getConstructor().getModifiers())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dynamically generated {@link ObjectInstantiator} for the given {@link InstantiatorKey}. There will always
|
||||
* be exactly one {@link ObjectInstantiator} instance per {@link PersistentEntity}.
|
||||
* Creates a dynamically generated {@link ObjectInstantiator} for the given {@link PersistentEntity}. There will
|
||||
* always be exactly one {@link ObjectInstantiator} instance per {@link PersistentEntity}.
|
||||
* <p>
|
||||
*
|
||||
* @param entity
|
||||
@@ -202,26 +206,26 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the arguments required to invoce the given constructor from the given {@link ParameterValueProvider}.
|
||||
* Extracts the arguments required to invoke the given constructor from the given {@link ParameterValueProvider}.
|
||||
*
|
||||
* @param constructor can be {@literal null}.
|
||||
* @param provider can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <P extends PersistentProperty<P>, T> Object[] extractInvocationArguments(
|
||||
Optional<? extends PreferredConstructor<? extends T, P>> constructor, ParameterValueProvider<P> provider) {
|
||||
PreferredConstructor<? extends T, P> constructor, ParameterValueProvider<P> provider) {
|
||||
|
||||
return constructor.map(it -> {
|
||||
if (provider == null || constructor == null || !constructor.hasParameters()) {
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
if (provider == null || !it.hasParameters()) {
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
List<Object> params = new ArrayList<>(constructor.getConstructor().getParameterCount());
|
||||
|
||||
return it.getParameters().stream()//
|
||||
.map(provider::getParameterValue)//
|
||||
.toArray();
|
||||
for (Parameter<?, P> parameter : constructor.getParameters()) {
|
||||
params.add(provider.getParameterValue(parameter));
|
||||
}
|
||||
|
||||
}).orElse(EMPTY_ARRAY);
|
||||
return params.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,9 +296,9 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new class for the given {@link InstantiatorKey}.
|
||||
* Generate a new class for the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param key
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public Class<?> generateCustomInstantiatorClass(PersistentEntity<?, ?> entity) {
|
||||
@@ -306,7 +310,7 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
private String generateClassName(PersistentEntity<?, ?> entity) {
|
||||
@@ -314,9 +318,10 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new class for the given {@link InstantiatorKey}.
|
||||
* Generate a new class for the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param key
|
||||
* @param internalClassName
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public byte[] generateBytecode(String internalClassName, PersistentEntity<?, ?> entity) {
|
||||
@@ -362,7 +367,9 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
mv.visitTypeInsn(NEW, entityTypeResourcePath);
|
||||
mv.visitInsn(DUP);
|
||||
|
||||
entity.getPersistenceConstructor().ifPresent(constructor -> {
|
||||
PreferredConstructor<?, ?> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor != null) {
|
||||
|
||||
Constructor<?> ctor = constructor.getConstructor();
|
||||
Class<?>[] parameterTypes = ctor.getParameterTypes();
|
||||
@@ -386,7 +393,7 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(0, 0); // (0, 0) = computed via ClassWriter.COMPUTE_MAXS
|
||||
mv.visitEnd();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -18,7 +18,6 @@ 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;
|
||||
@@ -31,7 +30,7 @@ import org.springframework.util.Assert;
|
||||
* {@link TypeInformationMapper} implementation that can be either set up using a {@link MappingContext} or manually set
|
||||
* up {@link Map} of {@link String} aliases to types. If a {@link MappingContext} is used the {@link Map} will be build
|
||||
* inspecting the {@link PersistentEntity} instances for type alias information.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ConfigurableTypeInformationMapper implements TypeInformationMapper {
|
||||
@@ -41,7 +40,7 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConfigurableTypeInformationMapper} for the given type map.
|
||||
*
|
||||
*
|
||||
* @param sourceTypeMap must not be {@literal null}.
|
||||
*/
|
||||
public ConfigurableTypeInformationMapper(Map<? extends Class<?>, String> sourceTypeMap) {
|
||||
@@ -66,7 +65,7 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@@ -79,7 +78,7 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(org.springframework.data.mapping.Alias)
|
||||
*/
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
return Optional.ofNullable(aliasToType.get(alias));
|
||||
public TypeInformation<?> resolveTypeFrom(Alias alias) {
|
||||
return aliasToType.get(alias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
@@ -52,7 +43,7 @@ import org.springframework.util.Assert;
|
||||
* around them. The converters build up two sets of types which store-specific basic types can be converted into and
|
||||
* from. These types will be considered simple ones (which means they neither need deeper inspection nor nested
|
||||
* conversion. Thus the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder} .
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
@@ -91,7 +82,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CustomConversions} instance registering the given converters.
|
||||
*
|
||||
*
|
||||
* @param storeConversions must not be {@literal null}.
|
||||
* @param converters must not be {@literal null}.
|
||||
*/
|
||||
@@ -126,7 +117,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link SimpleTypeHolder}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SimpleTypeHolder getSimpleTypeHolder() {
|
||||
@@ -136,7 +127,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns whether the given type is considered to be simple. That means it's either a general simple type or we have
|
||||
* a writing {@link Converter} registered for a particular type.
|
||||
*
|
||||
*
|
||||
* @see SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type
|
||||
* @return
|
||||
@@ -150,7 +141,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Populates the given {@link GenericConversionService} with the converters registered.
|
||||
*
|
||||
*
|
||||
* @param conversionService
|
||||
*/
|
||||
public void registerConvertersIn(ConverterRegistry conversionService) {
|
||||
@@ -162,7 +153,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Registers the given converter in the given {@link GenericConversionService}.
|
||||
*
|
||||
*
|
||||
* @param candidate must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
@@ -198,8 +189,8 @@ public class CustomConversions {
|
||||
/**
|
||||
* Registers the given {@link ConvertiblePair} as reading or writing pair depending on the type sides being basic
|
||||
* Mongo types.
|
||||
*
|
||||
* @param pair
|
||||
*
|
||||
* @param converterRegistration
|
||||
*/
|
||||
private void register(ConverterRegistration converterRegistration) {
|
||||
|
||||
@@ -230,7 +221,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
|
||||
* type into a Mongo native one.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
@@ -246,7 +237,7 @@ public class CustomConversions {
|
||||
* Returns the target type we can readTargetWriteLocl an inject of the given source type to. The returned type might
|
||||
* be a subclass of the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply
|
||||
* return the first target type matching or {@literal null} if no conversion can be found.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @param requestedTargetType must not be {@literal null}.
|
||||
* @return
|
||||
@@ -263,7 +254,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to readTargetWriteLocl into a Mongo native type. The
|
||||
* returned type might be a subclass of the given expected type though.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
@@ -277,7 +268,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to readTargetWriteLocl an object of the given source type
|
||||
* into an object of the given Mongo native target type.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return
|
||||
@@ -293,7 +284,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to readTargetReadLock the given source into the given target
|
||||
* type.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @param targetType must not be {@literal null}
|
||||
* @return
|
||||
@@ -309,7 +300,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Returns the actual target type for the given {@code sourceType} and {@code requestedTargetType}. Note that the
|
||||
* returned {@link Class} could be an assignable type to the given {@code requestedTargetType}.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return
|
||||
@@ -323,7 +314,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Inspects the given {@link ConvertiblePair}s for ones that have a source compatible type as source. Additionally
|
||||
* checks assignability of the target type if one is given.
|
||||
*
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param targetType can be {@literal null}.
|
||||
* @param pairs must not be {@literal null}.
|
||||
@@ -357,7 +348,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Conversion registration information.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -371,7 +362,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns whether the converter shall be used for writing.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isWriting() {
|
||||
@@ -380,7 +371,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns whether the converter shall be used for reading.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isReading() {
|
||||
@@ -389,7 +380,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns the actual conversion pair.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ConvertiblePair getConvertiblePair() {
|
||||
@@ -398,7 +389,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns whether the source type is a Mongo simple one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSimpleSourceType() {
|
||||
@@ -407,7 +398,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns whether the target type is a Mongo simple one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSimpleTargetType() {
|
||||
@@ -434,7 +425,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Creates a new {@link StoreConversions} for the given store-specific {@link SimpleTypeHolder} and the given
|
||||
* converters.
|
||||
*
|
||||
*
|
||||
* @param storeTypeHolder must not be {@literal null}.
|
||||
* @param converters must not be {@literal null}.
|
||||
* @return
|
||||
@@ -450,7 +441,7 @@ public class CustomConversions {
|
||||
/**
|
||||
* Creates a new {@link StoreConversions} for the given store-specific {@link SimpleTypeHolder} and the given
|
||||
* converters.
|
||||
*
|
||||
*
|
||||
* @param storeTypeHolder must not be {@literal null}.
|
||||
* @param converters must not be {@literal null}.
|
||||
* @return
|
||||
@@ -465,7 +456,7 @@ public class CustomConversions {
|
||||
|
||||
/**
|
||||
* Returns {@link ConverterRegistration}s for the given converter.
|
||||
*
|
||||
*
|
||||
* @param converter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -33,7 +32,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link TypeMapper}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
@@ -47,7 +46,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}. It will use a
|
||||
* {@link SimpleTypeInformationMapper} to calculate type aliases.
|
||||
*
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
*/
|
||||
public DefaultTypeMapper(TypeAliasAccessor<S> accessor) {
|
||||
@@ -57,7 +56,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
/**
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor} and {@link TypeInformationMapper}
|
||||
* s.
|
||||
*
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param mappers must not be {@literal null}.
|
||||
*/
|
||||
@@ -69,7 +68,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}, {@link MappingContext} and
|
||||
* additional {@link TypeInformationMapper}s. Will register a {@link MappingContextTypeInformationMapper} before the
|
||||
* given additional mappers.
|
||||
*
|
||||
*
|
||||
* @param accessor must not be {@literal null}.
|
||||
* @param mappingContext
|
||||
* @param additionalMappers must not be {@literal null}.
|
||||
@@ -96,7 +95,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object)
|
||||
*/
|
||||
public Optional<TypeInformation<?>> readType(S source) {
|
||||
public TypeInformation<?> readType(S source) {
|
||||
|
||||
Assert.notNull(source, "Source object must not be null!");
|
||||
|
||||
@@ -106,12 +105,23 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
/**
|
||||
* Tries to lookup a {@link TypeInformation} for the given alias from the cache and return it if found. If none is
|
||||
* found it'll consult the {@link TypeInformationMapper}s and cache the value found.
|
||||
*
|
||||
*
|
||||
* @param alias
|
||||
* @return
|
||||
*/
|
||||
private Optional<TypeInformation<?>> getFromCacheOrCreate(Alias alias) {
|
||||
return typeCache.computeIfAbsent(alias, key -> Optionals.firstNonEmpty(mappers, it -> it.resolveTypeFrom(alias)));
|
||||
private TypeInformation<?> getFromCacheOrCreate(Alias alias) {
|
||||
return typeCache.computeIfAbsent(alias, key -> {
|
||||
|
||||
for (TypeInformationMapper mapper : mappers) {
|
||||
TypeInformation<?> typeInformation = mapper.resolveTypeFrom(alias);
|
||||
|
||||
if (typeInformation != null) {
|
||||
return Optional.of(typeInformation);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,43 +133,49 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
Assert.notNull(source, "Source must not be null!");
|
||||
Assert.notNull(basicType, "Basic type must not be null!");
|
||||
|
||||
Optional<TypeInformation<? extends T>> calculated = getDefaultedTypeToBeUsed(source)//
|
||||
.map(it -> specializeOrDefault(it, basicType));
|
||||
Class<?> documentsTargetType = getDefaultedTypeToBeUsed(source);
|
||||
|
||||
return calculated.orElse(basicType);
|
||||
}
|
||||
if (documentsTargetType == null) {
|
||||
return basicType;
|
||||
}
|
||||
|
||||
private static <T> TypeInformation<? extends T> specializeOrDefault(Class<?> it, TypeInformation<T> type) {
|
||||
Class<T> rawType = basicType.getType();
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(it);
|
||||
Class<T> rawType = type.getType();
|
||||
boolean isMoreConcreteCustomType = rawType == null
|
||||
|| rawType.isAssignableFrom(documentsTargetType) && !rawType.equals(documentsTargetType);
|
||||
|
||||
return rawType.isAssignableFrom(it) && !rawType.equals(it) ? type.specialize(targetType) : type;
|
||||
if (!isMoreConcreteCustomType) {
|
||||
return basicType;
|
||||
}
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(documentsTargetType);
|
||||
|
||||
return (TypeInformation<? extends T>) (basicType != null ? basicType.specialize(targetType) : targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type discovered through {@link #readType(Object)} but defaulted to the one returned by
|
||||
* {@link #getFallbackTypeFor(Object)}.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
private Optional<Class<?>> getDefaultedTypeToBeUsed(S source) {
|
||||
private Class<?> getDefaultedTypeToBeUsed(S source) {
|
||||
|
||||
return readType(source)//
|
||||
.map(it -> readType(source))//
|
||||
.orElseGet(() -> getFallbackTypeFor(source))//
|
||||
.map(TypeInformation::getType);
|
||||
TypeInformation<?> documentsTargetTypeInformation = readType(source);
|
||||
documentsTargetTypeInformation = documentsTargetTypeInformation == null ? getFallbackTypeFor(source)
|
||||
: documentsTargetTypeInformation;
|
||||
return documentsTargetTypeInformation == null ? null : documentsTargetTypeInformation.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type fallback {@link TypeInformation} in case none could be extracted from the given source.
|
||||
*
|
||||
*
|
||||
* @param source will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Optional<TypeInformation<?>> getFallbackTypeFor(S source) {
|
||||
return Optional.empty();
|
||||
protected TypeInformation<?> getFallbackTypeFor(S source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -183,7 +199,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
/**
|
||||
* Returns the alias to be used for the given {@link TypeInformation}.
|
||||
*
|
||||
*
|
||||
* @param info must not be {@literal null}
|
||||
* @return the alias for the given {@link TypeInformation} or {@literal null} of none was found or all mappers
|
||||
* returned {@literal null}.
|
||||
|
||||
@@ -17,7 +17,6 @@ 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;
|
||||
@@ -31,7 +30,7 @@ import org.springframework.util.Assert;
|
||||
* {@link TypeInformationMapper} implementation that can be either set up using a {@link MappingContext} or manually set
|
||||
* up {@link Map} of {@link String} aliases to types. If a {@link MappingContext} is used the {@link Map} will be build
|
||||
* inspecting the {@link PersistentEntity} instances for type alias information.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@@ -43,7 +42,7 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
/**
|
||||
* Creates a {@link MappingContextTypeInformationMapper} from the given {@link MappingContext}. Inspects all
|
||||
* {@link PersistentEntity} instances for alias information and builds a {@link Map} of aliases to types from it.
|
||||
*
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public MappingContextTypeInformationMapper(MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext) {
|
||||
@@ -58,18 +57,27 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#createAliasFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Alias createAliasFor(TypeInformation<?> type) {
|
||||
|
||||
return typeMap.computeIfAbsent(type.getRawTypeInformation(), key -> verify(key, mappingContext.getPersistentEntity(key).map(PersistentEntity::getTypeAlias).orElse(Alias.NONE)));
|
||||
return typeMap.computeIfAbsent(type.getRawTypeInformation(), key -> {
|
||||
|
||||
PersistentEntity<?, ?> entity = mappingContext.getPersistentEntity(key);
|
||||
|
||||
if (entity == null || entity.getTypeAlias() == null) {
|
||||
return Alias.NONE;
|
||||
}
|
||||
|
||||
return verify(key, entity.getTypeAlias());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given alias to the cache in a {@literal null}-safe manner.
|
||||
*
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @param alias can be {@literal null}.
|
||||
*/
|
||||
@@ -103,29 +111,26 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
return alias;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.util.Optional)
|
||||
*/
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
public 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 (Entry<ClassTypeInformation<?>, Alias> entry : typeMap.entrySet()) {
|
||||
if (entry.getValue().hasSamePresentValueAs(alias)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
for (PersistentEntity<?, ?> entity : mappingContext.getPersistentEntities()) {
|
||||
|
||||
if (entity.getTypeAlias().hasValue(it)) {
|
||||
return entity.getTypeInformation().getRawTypeInformation();
|
||||
}
|
||||
if (entity.getTypeAlias().hasSamePresentValueAs(alias)) {
|
||||
return entity.getTypeInformation().getRawTypeInformation();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
PreferredConstructor<? extends T, P> constructor = entity.getPersistenceConstructor().orElse(null);
|
||||
PreferredConstructor<? extends T, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor == null) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -28,8 +28,9 @@ import org.springframework.util.ClassUtils;
|
||||
* Basic {@link TypeInformationMapper} implementation that interprets the alias handles as fully qualified class name
|
||||
* and tries to load a class with the given name to build {@link TypeInformation}. Returns the fully qualified class
|
||||
* name for alias creation.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
|
||||
@@ -39,23 +40,23 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
|
||||
* The implementation will simply interpret the given value as fully-qualified class name and try to load the class.
|
||||
* Will return {@literal null} in case the given {@link String} is empty.
|
||||
*
|
||||
* @param value the type to load, must not be {@literal null}.
|
||||
*
|
||||
* @param alias the type to load, must not be {@literal null}.
|
||||
* @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the
|
||||
* class cannot be loaded.
|
||||
*/
|
||||
@Override
|
||||
public Optional<TypeInformation<?>> resolveTypeFrom(Alias alias) {
|
||||
public TypeInformation<?> resolveTypeFrom(Alias alias) {
|
||||
|
||||
return alias.mapTyped(String.class)//
|
||||
.flatMap(it -> CACHE.computeIfAbsent(it, SimpleTypeInformationMapper::loadClass).map(type -> type));
|
||||
.flatMap(it -> CACHE.computeIfAbsent(it, SimpleTypeInformationMapper::loadClass)).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the given type information into the String representation that shall be stored. Default implementation simply
|
||||
* returns the fully-qualified class name.
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the String representation to be stored or {@literal null} if no type information shall be stored.
|
||||
*/
|
||||
public Alias createAliasFor(TypeInformation<?> type) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -15,29 +15,27 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Interface to abstract the mapping from a type alias to the actual type.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface TypeInformationMapper {
|
||||
|
||||
/**
|
||||
* Returns the actual {@link TypeInformation} to be used for the given alias.
|
||||
*
|
||||
*
|
||||
* @param alias can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Optional<TypeInformation<?>> resolveTypeFrom(Alias alias);
|
||||
TypeInformation<?> resolveTypeFrom(Alias alias);
|
||||
|
||||
/**
|
||||
* Returns the alias to be used for the given {@link TypeInformation}.
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2017 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.
|
||||
@@ -15,28 +15,26 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Interface to define strategies how to store type information in a store specific sink or source.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface TypeMapper<S> {
|
||||
|
||||
/**
|
||||
* Reads the {@link TypeInformation} from the given source.
|
||||
*
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Optional<TypeInformation<?>> readType(S source);
|
||||
TypeInformation<?> readType(S source);
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} from the given source if it is a more concrete type than the given default one.
|
||||
*
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param defaultType
|
||||
* @return
|
||||
@@ -45,7 +43,7 @@ public interface TypeMapper<S> {
|
||||
|
||||
/**
|
||||
* Writes type information for the given type into the given sink.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param dbObject must not be {@literal null}.
|
||||
*/
|
||||
@@ -53,7 +51,7 @@ public interface TypeMapper<S> {
|
||||
|
||||
/**
|
||||
* Writes type information for the given {@link TypeInformation} into the given sink.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param dbObject must not be {@literal null}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user