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
@@ -108,10 +108,10 @@ public class MappingAuditableBeanWrapperFactory extends DefaultAuditableBeanWrap
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
|
||||
this.createdByProperty = entity.getPersistentProperty(CreatedBy.class);
|
||||
this.createdDateProperty = entity.getPersistentProperty(CreatedDate.class);
|
||||
this.lastModifiedByProperty = entity.getPersistentProperty(LastModifiedBy.class);
|
||||
this.lastModifiedDateProperty = entity.getPersistentProperty(LastModifiedDate.class);
|
||||
this.createdByProperty = Optional.ofNullable(entity.getPersistentProperty(CreatedBy.class));
|
||||
this.createdDateProperty = Optional.ofNullable(entity.getPersistentProperty(CreatedDate.class));
|
||||
this.lastModifiedByProperty = Optional.ofNullable(entity.getPersistentProperty(LastModifiedBy.class));
|
||||
this.lastModifiedDateProperty = Optional.ofNullable(entity.getPersistentProperty(LastModifiedDate.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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}.
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@ public class Alias {
|
||||
}
|
||||
|
||||
public boolean hasSamePresentValueAs(Alias other) {
|
||||
return isPresent() && hasValue(other.value);
|
||||
return isPresent() && value.equals(other.value);
|
||||
}
|
||||
|
||||
public boolean isPresent() {
|
||||
@@ -64,4 +64,5 @@ public class Alias {
|
||||
public String toString() {
|
||||
return value.map(Object::toString).orElse("NONE");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -18,9 +18,10 @@ package org.springframework.data.mapping;
|
||||
|
||||
/**
|
||||
* Value object to capture {@link Association}s.
|
||||
*
|
||||
* @param the {@link PersistentProperty}s the association connects.
|
||||
*
|
||||
* @param <P> {@link PersistentProperty}s the association connects.
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class Association<P extends PersistentProperty<P>> {
|
||||
|
||||
@@ -29,7 +30,7 @@ public class Association<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Association} between the two given {@link PersistentProperty}s.
|
||||
*
|
||||
*
|
||||
* @param inverse
|
||||
* @param obverse
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -13,12 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
/**
|
||||
* Callback interface to implement functionality to be applied to a collection of {@link Association}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@@ -26,7 +25,7 @@ public interface AssociationHandler<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Processes the given {@link Association}.
|
||||
*
|
||||
*
|
||||
* @param association
|
||||
*/
|
||||
void doWithAssociation(Association<P> association);
|
||||
|
||||
@@ -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.
|
||||
@@ -16,42 +16,41 @@
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Represents a persistent entity.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Patryk Wasik
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* The entity name including any package prefix.
|
||||
*
|
||||
*
|
||||
* @return must never return {@literal null}
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the {@link PreferredConstructor} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
*
|
||||
* @return An empty {@link Optional} in case no suitable constructor for automatic construction can be found. This
|
||||
* usually indicates that the instantiation of the object of that persistent entity is done through either a
|
||||
* customer {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
*
|
||||
* @return {@literal null} in case no suitable constructor for automatic construction can be found. This usually
|
||||
* indicates that the instantiation of the object of that persistent entity is done through either a customer
|
||||
* {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
*/
|
||||
Optional<PreferredConstructor<T, P>> getPersistenceConstructor();
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referred to by a constructor argument of the
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @param property
|
||||
* @return true if the given {@link PersistentProperty} is referred to by a constructor argument or {@literal false}
|
||||
* if not or {@literal null}.
|
||||
@@ -60,7 +59,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the id property of the entity.
|
||||
*
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
@@ -68,7 +67,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is the version property of the entity.
|
||||
*
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
@@ -77,59 +76,80 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the id property of the {@link PersistentEntity}. Can be {@literal null} in case this is an entity
|
||||
* completely handled by a custom conversion.
|
||||
*
|
||||
*
|
||||
* @return the id property of the {@link PersistentEntity}.
|
||||
*/
|
||||
Optional<P> getIdProperty();
|
||||
P getIdProperty();
|
||||
|
||||
default P getRequiredIdProperty() {
|
||||
|
||||
return getIdProperty().orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Required identifier property not found for %s!", getType())));
|
||||
P property = getIdProperty();
|
||||
|
||||
if (property != null) {
|
||||
return property;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Required identifier property not found for %s!", getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version property of the {@link PersistentEntity}. Can be {@literal null} in case no version property is
|
||||
* available on the entity.
|
||||
*
|
||||
*
|
||||
* @return the version property of the {@link PersistentEntity}.
|
||||
*/
|
||||
Optional<P> getVersionProperty();
|
||||
P getVersionProperty();
|
||||
|
||||
default P getRequiredVersionProperty() {
|
||||
|
||||
P property = getVersionProperty();
|
||||
|
||||
if (property != null) {
|
||||
return property;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Required version property not found for %s!", getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@link PersistentProperty} instance by name.
|
||||
*
|
||||
*
|
||||
* @param name The name of the property
|
||||
* @return the {@link PersistentProperty} or {@literal Optional#empty()} if it doesn't exist.
|
||||
* @return the {@link PersistentProperty} or {@literal null} if it doesn't exist.
|
||||
*/
|
||||
Optional<P> getPersistentProperty(String name);
|
||||
P getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentProperty} with the given name.
|
||||
*
|
||||
*
|
||||
* @param name the name of the property, must not be {@literal null} or empty.
|
||||
* @return the {@link PersistentProperty} with the given name.
|
||||
* @throws IllegalArgumentException in case no property with the given name exists.
|
||||
*/
|
||||
default P getRequiredPersistentProperty(String name) {
|
||||
|
||||
return getPersistentProperty(name).orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("No property %s found for type %s!", name, getType())));
|
||||
P property = getPersistentProperty(name);
|
||||
|
||||
if (property != null) {
|
||||
return property;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Required identifier property not found for %s!", getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property equipped with an annotation of the given type.
|
||||
*
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
Optional<P> getPersistentProperty(Class<? extends Annotation> annotationType);
|
||||
P getPersistentProperty(Class<? extends Annotation> annotationType);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has an id property. If this call returns {@literal true},
|
||||
* {@link #getIdProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasIdProperty();
|
||||
@@ -137,14 +157,14 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has a version property. If this call returns {@literal true},
|
||||
* {@link #getVersionProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns the resolved Java type of this entity.
|
||||
*
|
||||
*
|
||||
* @return The underlying Java class for this entity
|
||||
*/
|
||||
Class<T> getType();
|
||||
@@ -152,14 +172,14 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the alias to be used when storing type information. Might be {@literal null} to indicate that there was no
|
||||
* alias defined through the mapping metadata.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Alias getTypeAlias();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} backing this {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<T> getTypeInformation();
|
||||
@@ -167,38 +187,47 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Applies the given {@link PropertyHandler} to all {@link PersistentProperty}s contained in this
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithProperties(PropertyHandler<P> handler);
|
||||
|
||||
void doWithProperties(SimplePropertyHandler handler);
|
||||
|
||||
Stream<P> getPersistentProperties();
|
||||
Iterable<P> getPersistentProperties();
|
||||
|
||||
/**
|
||||
* Applies the given {@link AssociationHandler} to all {@link Association} contained in this {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @param handler must not be {@literal null}.
|
||||
*/
|
||||
void doWithAssociations(AssociationHandler<P> handler);
|
||||
|
||||
void doWithAssociations(SimpleAssociationHandler handler);
|
||||
|
||||
Stream<Association<P>> getAssociations();
|
||||
Iterable<Association<P>> getAssociations();
|
||||
|
||||
/**
|
||||
* Looks up the annotation of the given type on the {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Checks whether the annotation of the given type is present on the {@link PersistentEntity}.
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
<A extends Annotation> boolean isAnnotationPresent(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentPropertyAccessor} to access property values of the given bean.
|
||||
*
|
||||
*
|
||||
* @param bean must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
@@ -207,7 +236,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the {@link IdentifierAccessor} for the given bean.
|
||||
*
|
||||
*
|
||||
* @param bean must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
|
||||
@@ -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.
|
||||
@@ -29,33 +29,34 @@ import org.springframework.data.util.TypeInformation;
|
||||
* @author Graeme Rocher
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} owning the current {@link PersistentProperty}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PersistentEntity<?, P> getOwner();
|
||||
|
||||
/**
|
||||
* The name of the property
|
||||
*
|
||||
*
|
||||
* @return The property name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The type of the property
|
||||
*
|
||||
*
|
||||
* @return The property type
|
||||
*/
|
||||
Class<?> getType();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the property.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
TypeInformation<?> getTypeInformation();
|
||||
@@ -64,7 +65,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* Returns the {@link TypeInformation} if the property references a {@link PersistentEntity}. Will return
|
||||
* {@literal null} in case it refers to a simple type. Will return {@link Collection}'s component type or the
|
||||
* {@link Map}'s value type transparently.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Iterable<? extends TypeInformation<?>> getPersistentEntityType();
|
||||
@@ -72,33 +73,40 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the getter method to access the property value if available. Might return {@literal null} in case there is
|
||||
* no getter method with a return type assignable to the actual property's type.
|
||||
*
|
||||
*
|
||||
* @return the getter method to access the property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Optional<Method> getGetter();
|
||||
Method getGetter();
|
||||
|
||||
/**
|
||||
* Returns the setter method to set a property value. Might return {@literal null} in case there is no setter
|
||||
* available.
|
||||
*
|
||||
*
|
||||
* @return the setter method to set a property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Optional<Method> getSetter();
|
||||
Method getSetter();
|
||||
|
||||
Optional<Field> getField();
|
||||
Field getField();
|
||||
|
||||
Optional<String> getSpelExpression();
|
||||
String getSpelExpression();
|
||||
|
||||
Optional<Association<P>> getAssociation();
|
||||
Association<P> getAssociation();
|
||||
|
||||
default Association<P> getRequiredAssociation() {
|
||||
return getAssociation().orElseThrow(() -> new IllegalStateException("No association found!"));
|
||||
|
||||
Association<P> association = getAssociation();
|
||||
|
||||
if (association != null) {
|
||||
return association;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No association found!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the type of the {@link PersistentProperty} is actually to be regarded as {@link PersistentEntity}
|
||||
* in turn.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isEntity();
|
||||
@@ -108,7 +116,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* This method is mainly used by {@link PersistentEntity} implementation to discover id property candidates on
|
||||
* {@link PersistentEntity} creation you should rather call {@link PersistentEntity#isIdProperty(PersistentProperty)}
|
||||
* to determine whether the current property is the id property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isIdProperty();
|
||||
@@ -119,42 +127,42 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* property candidates on {@link PersistentEntity} creation you should rather call
|
||||
* {@link PersistentEntity#isVersionProperty(PersistentProperty)} to determine whether the current property is the
|
||||
* version property of that {@link PersistentEntity} under consideration.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isVersionProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Collection}, {@link Iterable} or an array.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isCollectionLike();
|
||||
|
||||
/**
|
||||
* Returns whether the property is a {@link Map}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isMap();
|
||||
|
||||
/**
|
||||
* Returns whether the property is an array.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isArray();
|
||||
|
||||
/**
|
||||
* Returns whether the property is transient.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isTransient();
|
||||
|
||||
/**
|
||||
* Returns whether the current property is writable, i.e. if the value held for it shall be written to the data store.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @since 1.9
|
||||
*/
|
||||
@@ -162,7 +170,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the property is an {@link Association}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isAssociation();
|
||||
@@ -170,7 +178,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the component type of the type if it is a {@link java.util.Collection}. Will return the type of the key if
|
||||
* the property is a {@link java.util.Map}.
|
||||
*
|
||||
*
|
||||
* @return the component type, the map's key type or {@link Optional#empty()} if neither {@link java.util.Collection}
|
||||
* nor {@link java.util.Map}.
|
||||
*/
|
||||
@@ -178,14 +186,14 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the raw type as it's pulled from from the reflected property.
|
||||
*
|
||||
*
|
||||
* @return the raw type of the property.
|
||||
*/
|
||||
Class<?> getRawType();
|
||||
|
||||
/**
|
||||
* Returns the type of the values if the property is a {@link java.util.Map}.
|
||||
*
|
||||
*
|
||||
* @return the map's value type or {@link Optional#empty()} if no {@link java.util.Map}
|
||||
*/
|
||||
Optional<Class<?>> getMapValueType();
|
||||
@@ -193,7 +201,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the actual type of the property. This will be the original property type if no generics were used, the
|
||||
* component type for collection-like types and arrays as well as the value type for map properties.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> getActualType();
|
||||
@@ -201,25 +209,25 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Looks up the annotation of the given type on the {@link PersistentProperty}. Will inspect accessors and the
|
||||
* potentially backing field and traverse accessor methods to potentially available super types.
|
||||
*
|
||||
*
|
||||
* @param annotationType the annotation to look up, must not be {@literal null}.
|
||||
* @return the annotation of the given type.
|
||||
* @see AnnotationUtils#findAnnotation(Method, Class)
|
||||
*/
|
||||
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Looks up the annotation of the given type on the property and the owning type if no annotation can be found on it.
|
||||
* Usefull to lookup annotations that can be configured on the type but overridden on an individual property.
|
||||
*
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<A extends Annotation> Optional<A> findPropertyOrOwnerAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentProperty} has an annotation of the given type.
|
||||
*
|
||||
*
|
||||
* @param annotationType the annotation to lookup, must not be {@literal null}.
|
||||
* @return whether the {@link PersistentProperty} has an annotation of the given type.
|
||||
*/
|
||||
@@ -228,7 +236,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns whether property access shall be used for reading the property value. This means it will use the getter
|
||||
* instead of field access.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean usePropertyAccess();
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -38,11 +37,12 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to encapsulate the constructor to be used when mapping persistent data to objects.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Jon Brisbin
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
@@ -56,7 +56,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
|
||||
*
|
||||
*
|
||||
* @param constructor must not be {@literal null}.
|
||||
* @param parameters must not be {@literal null}.
|
||||
*/
|
||||
@@ -73,7 +73,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link Constructor}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Constructor<T> getConstructor() {
|
||||
@@ -82,7 +82,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the {@link Parameter}s of the constructor.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Streamable<Parameter<Object, P>> getParameters() {
|
||||
@@ -91,7 +91,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the constructor has {@link Parameter}s.
|
||||
*
|
||||
*
|
||||
* @see #isNoArgConstructor()
|
||||
* @return
|
||||
*/
|
||||
@@ -101,7 +101,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the constructor does not have any arguments.
|
||||
*
|
||||
*
|
||||
* @see #hasParameters()
|
||||
* @return
|
||||
*/
|
||||
@@ -111,7 +111,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns whether the constructor was explicitly selected (by {@link PersistenceConstructor}).
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplicitlyAnnotated() {
|
||||
@@ -121,7 +121,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referenced in a constructor argument of the
|
||||
* {@link PersistentEntity} backing this {@link PreferredConstructor}.
|
||||
*
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -165,7 +165,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* Returns whether the given {@link Parameter} is one referring to an enclosing class. That is in case the class this
|
||||
* {@link PreferredConstructor} belongs to is a member class actually. If that's the case the compiler creates a first
|
||||
* constructor argument of the enclosing class type.
|
||||
*
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -182,17 +182,17 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Value object to represent constructor parameters.
|
||||
*
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@EqualsAndHashCode(exclude = { "enclosingClassCache", "hasSpelExpression" })
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final Optional<String> name;
|
||||
private final String name;
|
||||
private final TypeInformation<T> type;
|
||||
private final Optional<String> key;
|
||||
private final Optional<PersistentEntity<T, P>> entity;
|
||||
private final String key;
|
||||
private final PersistentEntity<T, P> entity;
|
||||
|
||||
private final Lazy<Boolean> enclosingClassCache;
|
||||
private final Lazy<Boolean> hasSpelExpression;
|
||||
@@ -201,14 +201,13 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* Creates a new {@link Parameter} with the given name, {@link TypeInformation} as well as an array of
|
||||
* {@link Annotation}s. Will insprect the annotations for an {@link Value} annotation to lookup a key or an SpEL
|
||||
* expression to be evaluated.
|
||||
*
|
||||
*
|
||||
* @param name the name of the parameter, can be {@literal null}
|
||||
* @param type must not be {@literal null}
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public Parameter(Optional<String> name, TypeInformation<T> type, Annotation[] annotations,
|
||||
Optional<PersistentEntity<T, P>> entity) {
|
||||
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations, PersistentEntity<T, P> entity) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(annotations, "Annotations must not be null!");
|
||||
@@ -219,33 +218,38 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
this.entity = entity;
|
||||
|
||||
this.enclosingClassCache = Lazy.of(() -> {
|
||||
Class<T> owningType = entity.orElseThrow(IllegalStateException::new).getType();
|
||||
|
||||
if (entity == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Class<T> owningType = entity.getType();
|
||||
return owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
});
|
||||
|
||||
this.hasSpelExpression = Lazy.of(() -> getSpelExpression().map(StringUtils::hasText).orElse(false));
|
||||
this.hasSpelExpression = Lazy.of(() -> StringUtils.hasText(getSpelExpression()));
|
||||
}
|
||||
|
||||
private static Optional<String> getValue(Annotation[] annotations) {
|
||||
private static String getValue(Annotation[] annotations) {
|
||||
|
||||
return Arrays.stream(annotations)//
|
||||
.filter(it -> it.annotationType() == Value.class)//
|
||||
.findFirst().map(it -> ((Value) it).value())//
|
||||
.filter(StringUtils::hasText);
|
||||
.filter(StringUtils::hasText).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Optional<String> getName() {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} of the parameter.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TypeInformation<T> getType() {
|
||||
@@ -254,7 +258,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the raw resolved type of the parameter.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<T> getRawType() {
|
||||
@@ -263,35 +267,32 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Returns the key to be used when looking up a source data structure to populate the actual parameter value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Optional<String> getSpelExpression() {
|
||||
public String getSpelExpression() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the constructor parameter is equipped with a SpEL expression.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasSpelExpression() {
|
||||
return hasSpelExpression.get();
|
||||
return this.hasSpelExpression.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Parameter} maps the given {@link PersistentProperty}.
|
||||
*
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
//
|
||||
//
|
||||
return name.map(s -> entity
|
||||
.flatMap(it -> it.getPersistentProperty(s))
|
||||
.map(property::equals).orElse(false)).orElse(false);
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
return property != null && property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
private boolean isEnclosingClassParameter() {
|
||||
|
||||
@@ -17,8 +17,6 @@ package org.springframework.data.mapping;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* {@link IdentifierAccessor} that is aware of the target bean to obtain the identifier from so that it can generate a
|
||||
* more meaningful exception in case of an absent identifier and a call to {@link #getRequiredIdentifier()}.
|
||||
@@ -31,7 +29,7 @@ import java.util.function.Supplier;
|
||||
@RequiredArgsConstructor
|
||||
public abstract class TargetAwareIdentifierAccessor implements IdentifierAccessor {
|
||||
|
||||
private final Supplier<Object> target;
|
||||
private final Object target;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -46,6 +44,6 @@ public abstract class TargetAwareIdentifierAccessor implements IdentifierAccesso
|
||||
return identifier;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Could not obtain identifier from %s!", target.get()));
|
||||
throw new IllegalStateException(String.format("Could not obtain identifier from %s!", target));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,21 +160,10 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
public Optional<E> getPersistentEntity(Class<?> type) {
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(Class<?> type) {
|
||||
|
||||
return getPersistentEntity(type).orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("Couldn't find PersistentEntity for type %s!", type)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#hasPersistentEntityFor(java.lang.Class)
|
||||
@@ -191,7 +180,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public Optional<E> getPersistentEntity(TypeInformation<?> type) {
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
@@ -202,7 +191,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
Optional<E> entity = persistentEntities.get(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
return entity.orElse(null);
|
||||
}
|
||||
|
||||
} finally {
|
||||
@@ -218,32 +207,21 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
write.unlock();
|
||||
}
|
||||
|
||||
return NONE;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
throw new MappingException("Unknown persistent entity " + type);
|
||||
}
|
||||
|
||||
return addPersistentEntity(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
return getPersistentEntity(type)
|
||||
.orElseThrow(() -> new MappingException(String.format("Couldn't find PersistentEntity for type %s!", type)));
|
||||
return addPersistentEntity(type).orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public Optional<E> getPersistentEntity(P persistentProperty) {
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
|
||||
Assert.notNull(persistentProperty, "PersistentProperty must not be null!");
|
||||
|
||||
@@ -251,17 +229,6 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
return getPersistentEntity(typeInfo.getActualType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(P persistentProperty) {
|
||||
|
||||
return getPersistentEntity(persistentProperty).orElseThrow(() -> new IllegalArgumentException(
|
||||
String.format("Couldn't find PersistentEntity for type %s!", persistentProperty)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.Class, java.lang.String)
|
||||
@@ -317,14 +284,16 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
final DefaultPersistentPropertyPath<P> foo = path;
|
||||
final E bar = current;
|
||||
|
||||
Pair<DefaultPersistentPropertyPath<P>, E> pair = getPair(path, iterator, segment, current).orElseThrow(() -> {
|
||||
Pair<DefaultPersistentPropertyPath<P>, E> pair = getPair(path, iterator, segment, current);
|
||||
|
||||
if (pair == null) {
|
||||
|
||||
String source = StringUtils.collectionToDelimitedString(parts, ".");
|
||||
String resolvedPath = foo.toDotPath();
|
||||
|
||||
return new InvalidPersistentPropertyPath(source, type, segment, resolvedPath,
|
||||
throw new InvalidPersistentPropertyPath(source, type, segment, resolvedPath,
|
||||
String.format("No property %s found on %s!", segment, bar.getName()));
|
||||
});
|
||||
}
|
||||
|
||||
path = pair.getFirst();
|
||||
current = pair.getSecond();
|
||||
@@ -333,16 +302,17 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
return path;
|
||||
}
|
||||
|
||||
private Optional<Pair<DefaultPersistentPropertyPath<P>, E>> getPair(DefaultPersistentPropertyPath<P> path,
|
||||
private Pair<DefaultPersistentPropertyPath<P>, E> getPair(DefaultPersistentPropertyPath<P> path,
|
||||
Iterator<String> iterator, String segment, E entity) {
|
||||
|
||||
Optional<P> persistentProperty = entity.getPersistentProperty(segment);
|
||||
P property = entity.getPersistentProperty(segment);
|
||||
|
||||
return persistentProperty.map(it -> {
|
||||
if (property == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> type = it.getTypeInformation().getActualType();
|
||||
return Pair.of(path.append(it), iterator.hasNext() ? getRequiredPersistentEntity(type) : entity);
|
||||
});
|
||||
TypeInformation<?> type = property.getTypeInformation().getActualType();
|
||||
return Pair.of(path.append(property), iterator.hasNext() ? getRequiredPersistentEntity(type) : entity);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +526,10 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
}
|
||||
|
||||
entity.addPersistentProperty(property);
|
||||
property.getAssociation().ifPresent(entity::addAssociation);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getAssociation());
|
||||
}
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
return;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -43,14 +42,14 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
Collection<E> getPersistentEntities();
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link Class}. Will return {@link Optional#empty()} for types that
|
||||
* are considered simple ones.
|
||||
* Returns a {@link PersistentEntity} for the given {@link Class}. Will return {@code null} for types that are
|
||||
* considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Optional<E> getPersistentEntity(Class<?> type);
|
||||
E getPersistentEntity(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns a required {@link PersistentEntity} for the given {@link Class}. Will throw
|
||||
@@ -60,7 +59,16 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getRequiredPersistentEntity(Class<?> type);
|
||||
default E getRequiredPersistentEntity(Class<?> type) {
|
||||
|
||||
E entity = getPersistentEntity(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Couldn't find PersistentEntity for type %s!", type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link MappingContext} currently contains a {@link PersistentEntity} for the type.
|
||||
@@ -72,14 +80,14 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
boolean hasPersistentEntityFor(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}. Will return {@link Optional#empty()} for
|
||||
* types that are considered simple ones.
|
||||
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}. Will return {@code null} for types that
|
||||
* are considered simple ones.
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Optional<E> getPersistentEntity(TypeInformation<?> type);
|
||||
E getPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}. Will throw
|
||||
@@ -89,7 +97,16 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getRequiredPersistentEntity(TypeInformation<?> type);
|
||||
default E getRequiredPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
E entity = getPersistentEntity(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Couldn't find PersistentEntity for type %s!", type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
@@ -100,7 +117,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
Optional<E> getPersistentEntity(P persistentProperty);
|
||||
E getPersistentEntity(P persistentProperty);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
@@ -111,7 +128,17 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
E getRequiredPersistentEntity(P persistentProperty);
|
||||
default E getRequiredPersistentEntity(P persistentProperty) {
|
||||
|
||||
E entity = getPersistentEntity(persistentProperty);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Couldn't find PersistentEntity for property %s!", persistentProperty));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentProperty}s for the given path expression based on the given {@link PropertyPath}.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
@@ -19,12 +19,10 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategyFactorySupport;
|
||||
@@ -72,26 +70,25 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
*/
|
||||
@Override
|
||||
protected IsNewStrategy doGetIsNewStrategy(Class<?> type) {
|
||||
|
||||
return context.getPersistentEntity(type)//
|
||||
.flatMap(MappingContextIsNewStrategyFactory::getIsNewStrategy)//
|
||||
.orElseThrow(() -> new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type)));
|
||||
return MappingContextIsNewStrategyFactory.getIsNewStrategy(context.getRequiredPersistentEntity(type));
|
||||
}
|
||||
|
||||
private static Optional<IsNewStrategy> getIsNewStrategy(PersistentEntity<?, ?> entity) {
|
||||
private static IsNewStrategy getIsNewStrategy(PersistentEntity<?, ?> entity) {
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
|
||||
return entity.getVersionProperty().map(it -> PersistentPropertyInspectingIsNewStrategy.of(it,
|
||||
MappingContextIsNewStrategyFactory::propertyIsNullOrZeroNumber));
|
||||
return PersistentPropertyInspectingIsNewStrategy.of(entity.getRequiredVersionProperty(),
|
||||
MappingContextIsNewStrategyFactory::propertyIsNullOrZeroNumber);
|
||||
|
||||
} else if (entity.hasIdProperty()) {
|
||||
|
||||
return entity.getIdProperty().map(
|
||||
it -> PersistentPropertyInspectingIsNewStrategy.of(it, MappingContextIsNewStrategyFactory::propertyIsNull));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
if (entity.hasIdProperty()) {
|
||||
|
||||
return PersistentPropertyInspectingIsNewStrategy.of(entity.getRequiredIdProperty(),
|
||||
MappingContextIsNewStrategyFactory::propertyIsNull);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,13 +54,17 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
private final String name;
|
||||
private final TypeInformation<?> information;
|
||||
private final Class<?> rawType;
|
||||
private final Lazy<Optional<Association<P>>> association;
|
||||
private final Lazy<Association<P>> association;
|
||||
private final @Getter PersistentEntity<?, P> owner;
|
||||
private final @Getter(AccessLevel.PROTECTED) Property property;
|
||||
private final Lazy<Integer> hashCode;
|
||||
private final Lazy<Boolean> usePropertyAccess;
|
||||
private final Lazy<Optional<? extends TypeInformation<?>>> entityTypeInformation;
|
||||
|
||||
private final Method getter;
|
||||
private final Method setter;
|
||||
private final Field field;
|
||||
|
||||
public AbstractPersistentProperty(Property property, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
@@ -72,16 +76,19 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
this.information = PropertyPath.from(Pattern.quote(property.getName()), owner.getTypeInformation())
|
||||
.getTypeInformation();
|
||||
this.property = property;
|
||||
this.association = Lazy.of(() -> isAssociation() ? Optional.of(createAssociation()) : Optional.empty());
|
||||
this.association = Lazy.of(() -> isAssociation() ? createAssociation() : null);
|
||||
this.owner = owner;
|
||||
|
||||
this.hashCode = Lazy.of(property::hashCode);
|
||||
this.usePropertyAccess = Lazy
|
||||
.of(() -> owner.getType().isInterface() || getField().map(it -> it.equals(CAUSE_FIELD)).orElse(false));
|
||||
this.usePropertyAccess = Lazy.of(() -> owner.getType().isInterface() || CAUSE_FIELD.equals(getField()));
|
||||
this.entityTypeInformation = Lazy.of(() -> Optional.ofNullable(information.getActualType())//
|
||||
.filter(it -> !simpleTypeHolder.isSimpleType(it.getType()))//
|
||||
.filter(it -> !it.isCollectionLike())//
|
||||
.filter(it -> !it.isMap()));
|
||||
|
||||
this.getter = property.getGetter().orElse(null);
|
||||
this.setter = property.getSetter().orElse(null);
|
||||
this.field = property.getField().orElse(null);
|
||||
}
|
||||
|
||||
protected abstract Association<P> createAssociation();
|
||||
@@ -143,8 +150,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getGetter()
|
||||
*/
|
||||
@Override
|
||||
public Optional<Method> getGetter() {
|
||||
return property.getGetter();
|
||||
public Method getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,8 +159,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSetter()
|
||||
*/
|
||||
@Override
|
||||
public Optional<Method> getSetter() {
|
||||
return property.getSetter();
|
||||
public Method getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -161,8 +168,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getField()
|
||||
*/
|
||||
@Override
|
||||
public Optional<Field> getField() {
|
||||
return property.getField();
|
||||
public Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,8 +177,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getSpelExpression() {
|
||||
return Optional.empty();
|
||||
public String getSpelExpression() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,7 +213,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getAssociation()
|
||||
*/
|
||||
@Override
|
||||
public Optional<Association<P>> getAssociation() {
|
||||
public Association<P> getAssociation() {
|
||||
return association.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,16 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
|
||||
private static final String SPRING_DATA_PACKAGE = "org.springframework.data";
|
||||
|
||||
private final Optional<Value> value;
|
||||
private final Value value;
|
||||
private final Map<Class<? extends Annotation>, Optional<? extends Annotation>> annotationCache = new HashMap<>();
|
||||
|
||||
private final Lazy<Boolean> usePropertyAccess = Lazy.of(() -> findPropertyOrOwnerAnnotation(AccessType.class)//
|
||||
.map(it -> Type.PROPERTY.equals(it.value()))//
|
||||
.orElse(super.usePropertyAccess()));
|
||||
private final Lazy<Boolean> usePropertyAccess = Lazy.of(() -> {
|
||||
|
||||
AccessType accessType = findPropertyOrOwnerAnnotation(AccessType.class);
|
||||
|
||||
return accessType != null && Type.PROPERTY.equals(accessType.value()) || super.usePropertyAccess();
|
||||
});
|
||||
|
||||
private final Lazy<Boolean> isTransient = Lazy.of(() -> super.isTransient() || isAnnotationPresent(Transient.class)
|
||||
|| isAnnotationPresent(Value.class) || isAnnotationPresent(Autowired.class));
|
||||
|
||||
@@ -147,8 +151,13 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getSpelExpression() {
|
||||
return value.map(Value::value);
|
||||
public String getSpelExpression() {
|
||||
|
||||
if (value != null) {
|
||||
return value.value();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,20 +212,33 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType) {
|
||||
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
return doFindAnnotation(annotationType).orElse(null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
|
||||
|
||||
if (annotationCache != null && annotationCache.containsKey(annotationType)) {
|
||||
return (Optional<A>) annotationCache.get(annotationType);
|
||||
}
|
||||
|
||||
return cacheAndReturn(annotationType,
|
||||
getAccessors()//
|
||||
.map(it -> it.map(inner -> AnnotatedElementUtils.findMergedAnnotation(inner, annotationType)))//
|
||||
.flatMap(Optionals::toStream)//
|
||||
.findFirst());
|
||||
return cacheAndReturn(annotationType, getAccessors()//
|
||||
.flatMap(it -> {
|
||||
|
||||
A mergedAnnotation = AnnotatedElementUtils.findMergedAnnotation(it, annotationType);
|
||||
|
||||
if (mergedAnnotation == null) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
return Stream.of(mergedAnnotation);
|
||||
})//
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -224,10 +246,11 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @see org.springframework.data.mapping.PersistentProperty#findPropertyOrOwnerAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <A extends Annotation> Optional<A> findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
|
||||
Optional<A> annotation = findAnnotation(annotationType);
|
||||
return annotation.isPresent() ? annotation : getOwner().findAnnotation(annotationType);
|
||||
A annotation = findAnnotation(annotationType);
|
||||
|
||||
return annotation != null ? annotation : getOwner().findAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,7 +272,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @return
|
||||
*/
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return findAnnotation(annotationType).isPresent();
|
||||
return doFindAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -280,7 +303,9 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
return builder + super.toString();
|
||||
}
|
||||
|
||||
private Stream<Optional<? extends AnnotatedElement>> getAccessors() {
|
||||
return Stream.of(getGetter(), getSetter(), getField());
|
||||
private Stream<? extends AnnotatedElement> getAccessors() {
|
||||
|
||||
return Optionals.toStream(Optional.ofNullable(getGetter()), Optional.ofNullable(getSetter()),
|
||||
Optional.ofNullable(getField()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -57,17 +56,18 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)!";
|
||||
private static final String NULL_ASSOCIATION = "%s.addAssociation(…) was called with a null association! Usually indicates a problem in a Spring Data MappingContext implementation. Be sure to file a bug at https://jira.spring.io!";
|
||||
|
||||
private final Optional<PreferredConstructor<T, P>> constructor;
|
||||
private final PreferredConstructor<T, P> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final List<P> properties;
|
||||
private final Optional<Comparator<P>> comparator;
|
||||
private final List<P> persistentPropertiesCache;
|
||||
private final Comparator<P> comparator;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private final Map<String, Optional<P>> propertyCache;
|
||||
private final Map<String, P> propertyCache;
|
||||
private final Map<Class<? extends Annotation>, Optional<Annotation>> annotationCache;
|
||||
|
||||
private Optional<P> idProperty = Optional.empty();
|
||||
private Optional<P> versionProperty = Optional.empty();
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
private PersistentPropertyAccessorFactory propertyAccessorFactory;
|
||||
|
||||
private final Lazy<Alias> typeAlias;
|
||||
@@ -78,7 +78,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information) {
|
||||
this(information, Optional.empty());
|
||||
this(information, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,16 +89,16 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @param information must not be {@literal null}.
|
||||
* @param comparator can be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information, Optional<Comparator<P>> comparator) {
|
||||
public BasicPersistentEntity(TypeInformation<T> information, Comparator<P> comparator) {
|
||||
|
||||
Assert.notNull(information, "Information must not be null!");
|
||||
|
||||
this.information = information;
|
||||
this.properties = new ArrayList<>();
|
||||
this.persistentPropertiesCache = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
this.constructor = new PreferredConstructorDiscoverer<>(this).getConstructor();
|
||||
this.associations = comparator.<Set<Association<P>>> map(it -> new TreeSet<>(new AssociationComparator<>(it)))
|
||||
.orElseGet(HashSet::new);
|
||||
this.associations = comparator == null ? new HashSet<>() : new TreeSet<>(new AssociationComparator<P>(comparator));
|
||||
|
||||
this.propertyCache = new HashMap<>();
|
||||
this.annotationCache = new HashMap<>();
|
||||
@@ -114,7 +114,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
public Optional<PreferredConstructor<T, P>> getPersistenceConstructor() {
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor.map(it -> it.isConstructorParameter(property)).orElse(false);
|
||||
return constructor != null && constructor.isConstructorParameter(property);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -131,7 +131,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isIdProperty(PersistentProperty<?> property) {
|
||||
return this.idProperty.map(it -> it.equals(property)).orElse(false);
|
||||
return idProperty != null && idProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -139,7 +139,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isVersionProperty(PersistentProperty<?> property) {
|
||||
return this.versionProperty.map(it -> it.equals(property)).orElse(false);
|
||||
return versionProperty != null && versionProperty.equals(property);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,7 +154,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
public Optional<P> getIdProperty() {
|
||||
public P getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
public Optional<P> getVersionProperty() {
|
||||
public P getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
return idProperty.isPresent();
|
||||
return idProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -179,7 +179,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
|
||||
*/
|
||||
public boolean hasVersionProperty() {
|
||||
return versionProperty.isPresent();
|
||||
return versionProperty != null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -196,26 +196,31 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
properties.add(property);
|
||||
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
persistentPropertiesCache.add(property);
|
||||
}
|
||||
|
||||
if (!propertyCache.containsKey(property.getName())) {
|
||||
propertyCache.put(property.getName(), Optional.of(property));
|
||||
propertyCache.put(property.getName(), property);
|
||||
}
|
||||
|
||||
P candidate = returnPropertyIfBetterIdPropertyCandidateOrNull(property);
|
||||
|
||||
if (candidate != null) {
|
||||
this.idProperty = Optional.of(candidate);
|
||||
this.idProperty = candidate;
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
this.versionProperty.ifPresent(it -> {
|
||||
if (this.versionProperty != null) {
|
||||
|
||||
throw new MappingException(
|
||||
String.format("Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), it.getField()));
|
||||
});
|
||||
throw new MappingException(String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!",
|
||||
property.getField(), this.versionProperty.getField()));
|
||||
}
|
||||
|
||||
this.versionProperty = Optional.of(property);
|
||||
this.versionProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,10 +236,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
return null;
|
||||
}
|
||||
|
||||
this.idProperty.ifPresent(it -> {
|
||||
if (this.idProperty != null) {
|
||||
throw new MappingException(String.format("Attempt to add id property %s but already have property %s registered "
|
||||
+ "as id. Check your mapping configuration!", property.getField(), it.getField()));
|
||||
});
|
||||
+ "as id. Check your mapping configuration!", property.getField(), this.idProperty.getField()));
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
@@ -256,15 +261,15 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
public Optional<P> getPersistentProperty(String name) {
|
||||
public P getPersistentProperty(String name) {
|
||||
|
||||
Optional<P> property = propertyCache.get(name);
|
||||
P property = propertyCache.get(name);
|
||||
|
||||
if (property != null) {
|
||||
return property;
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -272,7 +277,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Optional<P> getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
public P getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
@@ -280,12 +285,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
.filter(it -> it.isAnnotationPresent(annotationType))//
|
||||
.findAny();
|
||||
|
||||
if (property.isPresent()) {
|
||||
return property;
|
||||
}
|
||||
|
||||
return associations.stream().map(Association::getInverse)//
|
||||
.filter(it -> it.isAnnotationPresent(annotationType)).findAny();
|
||||
return property.orElseGet(() -> associations.stream().map(Association::getInverse)//
|
||||
.filter(it -> it.isAnnotationPresent(annotationType)).findAny().orElse(null));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -320,10 +321,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
Assert.notNull(handler, "PropertyHandler must not be null!");
|
||||
|
||||
for (P property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
for (P property : persistentPropertiesCache) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,10 +335,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (PersistentProperty<?> property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
for (PersistentProperty<?> property : persistentPropertiesCache) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,10 +345,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperties()
|
||||
*/
|
||||
@Override
|
||||
public Stream<P> getPersistentProperties() {
|
||||
|
||||
return properties.stream()//
|
||||
.filter(it -> !it.isTransient() && !it.isAssociation());
|
||||
public Iterable<P> getPersistentProperties() {
|
||||
return persistentPropertiesCache;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -385,8 +380,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getAssociations()
|
||||
*/
|
||||
@Override
|
||||
public Stream<Association<P>> getAssociations() {
|
||||
return associations.stream();
|
||||
public Iterable<Association<P>> getAssociations() {
|
||||
return associations;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -395,9 +390,22 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType) {
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
return (A) doFindAnnotation(annotationType).orElse(null);
|
||||
}
|
||||
|
||||
return (Optional<A>) annotationCache.computeIfAbsent(annotationType,
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isAnnotationPresent(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <A extends Annotation> boolean isAnnotationPresent(Class<A> annotationType) {
|
||||
return doFindAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
private <A extends Annotation> Optional<Annotation> doFindAnnotation(Class<A> annotationType) {
|
||||
|
||||
return annotationCache.computeIfAbsent(annotationType,
|
||||
it -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), it)));
|
||||
}
|
||||
|
||||
@@ -406,7 +414,11 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
|
||||
*/
|
||||
public void verify() {
|
||||
comparator.ifPresent(it -> properties.sort(it));
|
||||
|
||||
if (comparator != null) {
|
||||
properties.sort(comparator);
|
||||
persistentPropertiesCache.sort(comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -455,7 +467,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
private static class AbsentIdentifierAccessor extends TargetAwareIdentifierAccessor {
|
||||
|
||||
public AbsentIdentifierAccessor(Object target) {
|
||||
super(() -> target);
|
||||
super(target);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -57,20 +56,20 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
Field field = property.getField().get();
|
||||
Field field = property.getField();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, value);
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<Method> setter = property.getSetter();
|
||||
Method setter = property.getSetter();
|
||||
|
||||
setter.ifPresent(it -> {
|
||||
if (setter != null) {
|
||||
|
||||
ReflectionUtils.makeAccessible(it);
|
||||
ReflectionUtils.invokeMethod(it, bean, value);
|
||||
});
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, value);
|
||||
}
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException("Could not set object property!", e);
|
||||
@@ -103,18 +102,20 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
Field field = property.getField().get();
|
||||
Field field = property.getField();
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return ReflectionUtils.getField(field, bean);
|
||||
}
|
||||
|
||||
Optional<Method> getter = property.getGetter();
|
||||
Method getter = property.getGetter();
|
||||
|
||||
return getter.map(it -> {
|
||||
if (getter != null) {
|
||||
|
||||
ReflectionUtils.makeAccessible(it);
|
||||
return (S) ReflectionUtils.invokeMethod(it, bean);
|
||||
}).orElse(null);
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
return ReflectionUtils.invokeMethod(getter, bean);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -17,8 +17,8 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
/**
|
||||
* {@link FieldNamingStrategy} that abbreviates field names by using the very first letter of the camel case parts of
|
||||
* the {@link MongoPersistentProperty}'s name.
|
||||
*
|
||||
* the {@link org.springframework.data.mapping.PersistentProperty}'s name.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@@ -31,7 +31,7 @@ public class CamelCaseAbbreviatingFieldNamingStrategy extends CamelCaseSplitting
|
||||
super("");
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.CamelCaseSplittingFieldNamingStrategy#preparePart(java.lang.String)
|
||||
*/
|
||||
|
||||
@@ -350,20 +350,23 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
for (PersistentProperty<?> property : persistentProperties) {
|
||||
|
||||
property.getSetter().filter(it -> generateMethodHandle(entity, it))
|
||||
.ifPresent(it -> cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, setterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd());
|
||||
property.getGetter().filter(it -> generateMethodHandle(entity, it))
|
||||
.ifPresent(it -> cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, getterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd());
|
||||
if (generateMethodHandle(entity, property.getSetter())) {
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, setterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
}
|
||||
|
||||
property.getField().filter(it -> generateSetterMethodHandle(entity, it)).ifPresent(it -> {
|
||||
if (generateMethodHandle(entity, property.getGetter())) {
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, getterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
}
|
||||
|
||||
if (generateSetterMethodHandle(entity, property.getField())) {
|
||||
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,15 +478,18 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
if (property.usePropertyAccess()) {
|
||||
|
||||
property.getGetter().filter(it -> generateMethodHandle(entity, it))
|
||||
.ifPresent(it -> visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName));
|
||||
if (generateMethodHandle(entity, property.getGetter())) {
|
||||
visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
|
||||
property.getSetter().filter(it -> generateMethodHandle(entity, it))
|
||||
.ifPresent(it -> visitPropertySetterInitializer(property, mv, entityClasses, internalClassName));
|
||||
if (generateMethodHandle(entity, property.getSetter())) {
|
||||
visitPropertySetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
}
|
||||
|
||||
property.getField().filter(it -> generateSetterMethodHandle(entity, it))
|
||||
.ifPresent(it -> visitFieldGetterSetterInitializer(property, mv, entityClasses, internalClassName));
|
||||
if (generateSetterMethodHandle(entity, property.getField())) {
|
||||
visitFieldGetterSetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitLabel(l1);
|
||||
@@ -511,8 +517,13 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static List<Class<?>> getPropertyDeclaratingClasses(List<PersistentProperty<?>> persistentProperties) {
|
||||
|
||||
return persistentProperties.stream().flatMap(property -> {
|
||||
return Optionals.toStream(property.getField(), property.getGetter(), property.getSetter())
|
||||
return Optionals
|
||||
.toStream(Optional.ofNullable(property.getField()), Optional.ofNullable(property.getGetter()),
|
||||
Optional.ofNullable(property.getSetter()))
|
||||
|
||||
// keep it a lambda to infer the correct types, preventing
|
||||
// LambdaConversionException: Invalid receiver type class java.lang.reflect.AccessibleObject; not a subtype
|
||||
// of implementation type interface java.lang.reflect.Member
|
||||
.map(it -> it.getDeclaringClass());
|
||||
|
||||
}).collect(Collectors.collectingAndThen(Collectors.toSet(), it -> new ArrayList<>(it)));
|
||||
@@ -526,12 +537,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// getter = <entity>.class.getDeclaredMethod()
|
||||
Optional<Method> getter = property.getGetter();
|
||||
Method getter = property.getGetter();
|
||||
|
||||
getter.ifPresent(it -> {
|
||||
if (getter != null) {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, getter.getDeclaringClass()));
|
||||
mv.visitLdcInsn(getter.getName());
|
||||
mv.visitInsn(ICONST_0);
|
||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS);
|
||||
|
||||
@@ -549,9 +560,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflect", String.format("(%s)%s",
|
||||
referenceName(JAVA_LANG_REFLECT_METHOD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!getter.isPresent()) {
|
||||
if (getter == null) {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
}
|
||||
|
||||
@@ -566,22 +577,22 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// setter = <entity>.class.getDeclaredMethod()
|
||||
Optional<Method> setter = property.getSetter();
|
||||
Method setter = property.getSetter();
|
||||
|
||||
setter.ifPresent(it -> {
|
||||
if (setter != null) {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, setter.getDeclaringClass()));
|
||||
mv.visitLdcInsn(setter.getName());
|
||||
|
||||
mv.visitInsn(ICONST_1);
|
||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitInsn(ICONST_0);
|
||||
|
||||
Class<?> parameterType = it.getParameterTypes()[0];
|
||||
Class<?> parameterType = setter.getParameterTypes()[0];
|
||||
|
||||
if (parameterType.isPrimitive()) {
|
||||
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(autoboxType(it.getParameterTypes()[0])), "TYPE",
|
||||
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(autoboxType(setter.getParameterTypes()[0])), "TYPE",
|
||||
referenceName(JAVA_LANG_CLASS));
|
||||
} else {
|
||||
mv.visitLdcInsn(Type.getType(referenceName(parameterType)));
|
||||
@@ -603,9 +614,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflect", String.format("(%s)%s",
|
||||
referenceName(JAVA_LANG_REFLECT_METHOD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!setter.isPresent()) {
|
||||
if (setter == null) {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
}
|
||||
|
||||
@@ -620,10 +631,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// field = <entity>.class.getDeclaredField()
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
Field field = property.getField();
|
||||
if (field != null) {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, field.getDeclaringClass()));
|
||||
mv.visitLdcInsn(field.getName());
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASS, "getDeclaredField",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_STRING), referenceName(JAVA_LANG_REFLECT_FIELD)), false);
|
||||
mv.visitVarInsn(ASTORE, 1);
|
||||
@@ -648,7 +661,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
"(%s)%s", referenceName(JAVA_LANG_REFLECT_FIELD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
mv.visitFieldInsn(PUTSTATIC, internalClassName, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void visitBeanGetter(PersistentEntity<?, ?> entity, String internalClassName, ClassWriter cw) {
|
||||
@@ -778,7 +791,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitLabel(propertyStackMap.get(property.getName()).label);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
|
||||
if (property.getGetter().isPresent() || property.getField().isPresent()) {
|
||||
if (property.getGetter() != null || property.getField() != null) {
|
||||
visitGetProperty0(entity, property, mv, internalClassName);
|
||||
} else {
|
||||
mv.visitJumpInsn(GOTO, dfltLabel);
|
||||
@@ -797,9 +810,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static void visitGetProperty0(PersistentEntity<?, ?> entity, PersistentProperty<?> property,
|
||||
MethodVisitor mv, String internalClassName) {
|
||||
|
||||
property.getGetter().filter(it -> property.usePropertyAccess()).map(it -> {
|
||||
Method getter = property.getGetter();
|
||||
if (property.usePropertyAccess() && getter != null) {
|
||||
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
if (generateMethodHandle(entity, getter)) {
|
||||
// $getter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, getterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -811,42 +825,35 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
int invokeOpCode = INVOKEVIRTUAL;
|
||||
Class<?> declaringClass = it.getDeclaringClass();
|
||||
Class<?> declaringClass = getter.getDeclaringClass();
|
||||
boolean interfaceDefinition = declaringClass.isInterface();
|
||||
|
||||
if (interfaceDefinition) {
|
||||
invokeOpCode = INVOKEINTERFACE;
|
||||
}
|
||||
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(declaringClass), it.getName(),
|
||||
String.format("()%s", signatureTypeName(it.getReturnType())), interfaceDefinition);
|
||||
autoboxIfNeeded(it.getReturnType(), autoboxType(it.getReturnType()), mv);
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(declaringClass), getter.getName(),
|
||||
String.format("()%s", signatureTypeName(getter.getReturnType())), interfaceDefinition);
|
||||
autoboxIfNeeded(getter.getReturnType(), autoboxType(getter.getReturnType()), mv);
|
||||
}
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}).orElseGet(() -> {
|
||||
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
// $fieldGetter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
|
||||
} else {
|
||||
// bean.field
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitFieldInsn(GETFIELD, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
signatureTypeName(it.getType()));
|
||||
autoboxIfNeeded(it.getType(), autoboxType(it.getType()), mv);
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
Field field = property.getField();
|
||||
if (generateMethodHandle(entity, field)) {
|
||||
// $fieldGetter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
|
||||
} else {
|
||||
// bean.field
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitFieldInsn(GETFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
|
||||
signatureTypeName(field.getType()));
|
||||
autoboxIfNeeded(field.getType(), autoboxType(field.getType()), mv);
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
}
|
||||
@@ -947,7 +954,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitLabel(propertyStackMap.get(property.getName()).label);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
|
||||
if (property.getSetter().isPresent() || property.getField().isPresent()) {
|
||||
if (property.getSetter() != null || property.getField() != null) {
|
||||
visitSetProperty0(entity, property, mv, internalClassName);
|
||||
} else {
|
||||
mv.visitJumpInsn(GOTO, dfltLabel);
|
||||
@@ -966,11 +973,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static void visitSetProperty0(PersistentEntity<?, ?> entity, PersistentProperty<?> property,
|
||||
MethodVisitor mv, String internalClassName) {
|
||||
|
||||
Optional<Method> setter = property.getSetter();
|
||||
Method setter = property.getSetter();
|
||||
if (property.usePropertyAccess() && setter != null) {
|
||||
|
||||
setter.filter(it -> property.usePropertyAccess()).map(it -> {
|
||||
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
if (generateMethodHandle(entity, setter)) {
|
||||
// $setter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, setterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -983,28 +989,26 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
Class<?> parameterType = it.getParameterTypes()[0];
|
||||
Class<?> parameterType = setter.getParameterTypes()[0];
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(parameterType)));
|
||||
autoboxIfNeeded(autoboxType(parameterType), parameterType, mv);
|
||||
|
||||
int invokeOpCode = INVOKEVIRTUAL;
|
||||
Class<?> declaringClass = it.getDeclaringClass();
|
||||
Class<?> declaringClass = setter.getDeclaringClass();
|
||||
boolean interfaceDefinition = declaringClass.isInterface();
|
||||
|
||||
if (interfaceDefinition) {
|
||||
invokeOpCode = INVOKEINTERFACE;
|
||||
}
|
||||
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(setter.getDeclaringClass()), setter.getName(),
|
||||
String.format("(%s)V", signatureTypeName(parameterType)), interfaceDefinition);
|
||||
}
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}).orElseGet(() -> {
|
||||
|
||||
property.getField().ifPresent(it -> {
|
||||
if (generateSetterMethodHandle(entity, it)) {
|
||||
Field field = property.getField();
|
||||
if (field != null) {
|
||||
if (generateSetterMethodHandle(entity, field)) {
|
||||
// $fieldSetter.invoke(bean, object)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -1017,17 +1021,15 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
Class<?> fieldType = it.getType();
|
||||
Class<?> fieldType = field.getType();
|
||||
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(fieldType)));
|
||||
autoboxIfNeeded(autoboxType(fieldType), fieldType, mv);
|
||||
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
|
||||
signatureTypeName(fieldType));
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
}
|
||||
@@ -1094,6 +1096,11 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
}
|
||||
|
||||
private static boolean generateSetterMethodHandle(PersistentEntity<?, ?> entity, Field field) {
|
||||
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return generateMethodHandle(entity, field) || Modifier.isFinal(field.getModifiers());
|
||||
}
|
||||
|
||||
@@ -1104,6 +1111,10 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
*/
|
||||
private static boolean generateMethodHandle(PersistentEntity<?, ?> entity, Member member) {
|
||||
|
||||
if (member == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isAccessible(entity)) {
|
||||
|
||||
if (Modifier.isProtected(member.getModifiers()) || isDefault(member.getModifiers())) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
@@ -23,7 +24,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
/**
|
||||
* {@link ParameterValueProvider} implementation that evaluates the {@link Parameter}s key against
|
||||
* {@link SpelExpressionParser} and {@link EvaluationContext}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
|
||||
@@ -32,7 +33,7 @@ public class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
|
||||
private final SpELContext factory;
|
||||
|
||||
/**
|
||||
* @param parser
|
||||
* @param source
|
||||
* @param factory
|
||||
*/
|
||||
public DefaultSpELExpressionEvaluator(Object source, SpELContext factory) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -19,7 +19,7 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* SPI to determine how to name document fields in cases the field name is not manually defined.
|
||||
*
|
||||
*
|
||||
* @see PropertyNameFieldNamingStrategy
|
||||
* @see CamelCaseAbbreviatingFieldNamingStrategy
|
||||
* @see SnakeCaseFieldNamingStrategy
|
||||
@@ -29,8 +29,8 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
public interface FieldNamingStrategy {
|
||||
|
||||
/**
|
||||
* Returns the field name to be used for the given {@link MongoPersistentProperty}.
|
||||
*
|
||||
* Returns the field name to be used for the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null} or empty;
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,7 @@ public class IdPropertyIdentifierAccessor extends TargetAwareIdentifierAccessor
|
||||
*/
|
||||
public IdPropertyIdentifierAccessor(PersistentEntity<?, ?> entity, Object target) {
|
||||
|
||||
super(() -> target);
|
||||
super(target);
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
Assert.isTrue(entity.hasIdProperty(), "PersistentEntity must have an identifier property!");
|
||||
|
||||
@@ -69,8 +69,8 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
super(buildExceptionMessage(entity, arguments, message), cause);
|
||||
|
||||
this.entityType = entity.map(PersistentEntity::getType).orElse(null);
|
||||
this.constructor = entity.flatMap(PersistentEntity::getPersistenceConstructor)
|
||||
.map(PreferredConstructor::getConstructor).orElse(null);
|
||||
this.constructor = entity.map(PersistentEntity::getPersistenceConstructor).map(PreferredConstructor::getConstructor)
|
||||
.orElse(null);
|
||||
this.constructorArguments = arguments;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
|
||||
return entity.map(it -> {
|
||||
|
||||
Optional<? extends PreferredConstructor<?, ?>> constructor = it.getPersistenceConstructor();
|
||||
Optional<? extends PreferredConstructor<?, ?>> constructor = Optional.ofNullable(it.getPersistenceConstructor());
|
||||
|
||||
List<String> toStringArgs = new ArrayList<>(arguments.size());
|
||||
for (Object o : arguments) {
|
||||
|
||||
@@ -62,13 +62,13 @@ public class PersistentEntityParameterValueProvider<P extends PersistentProperty
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor().orElse(null);
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor.isEnclosingClassParameter(parameter)) {
|
||||
return (T) parent;
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(parameter.getName().orElse(null)).orElse(null);
|
||||
P property = entity.getPersistentProperty(parameter.getName());
|
||||
|
||||
if (property == null) {
|
||||
throw new MappingException(String.format("No property %s found on entity %s to bind constructor parameter to!",
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.data.mapping.model;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -31,20 +30,21 @@ import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Roman Rodov
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private Optional<PreferredConstructor<T, P>> constructor;
|
||||
private PreferredConstructor<T, P> constructor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(Class<T> type) {
|
||||
@@ -53,20 +53,20 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given {@link PersistentEntity}.
|
||||
*
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(PersistentEntity<T, P> entity) {
|
||||
this(entity.getTypeInformation(), Optional.ofNullable(entity));
|
||||
this(entity.getTypeInformation(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
*
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity
|
||||
*/
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, Optional<PersistentEntity<T, P>> entity) {
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, PersistentEntity<T, P> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
@@ -83,13 +83,13 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
this.constructor = Optional.of(preferredConstructor);
|
||||
this.constructor = preferredConstructor;
|
||||
return;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (this.constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
this.constructor = Optional.of(preferredConstructor);
|
||||
this.constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
@@ -100,13 +100,13 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
this.constructor = Optional.empty();
|
||||
this.constructor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PreferredConstructor<T, P> buildPreferredConstructor(Constructor<?> constructor,
|
||||
TypeInformation<T> typeInformation, Optional<PersistentEntity<T, P>> entity) {
|
||||
TypeInformation<T> typeInformation, PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
@@ -121,7 +121,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
Optional<String> name = Optional.ofNullable(parameterNames == null ? null : parameterNames[i]);
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
@@ -133,10 +133,10 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
/**
|
||||
* Returns the discovered {@link PreferredConstructor}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Optional<PreferredConstructor<T, P>> getConstructor() {
|
||||
public PreferredConstructor<T, P> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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,8 +18,8 @@ package org.springframework.data.mapping.model;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* {@link FieldNamingStrategy} simply using the {@link MongoPersistentProperty}'s name.
|
||||
*
|
||||
* {@link FieldNamingStrategy} simply using the {@link PersistentProperty}'s name.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
@@ -65,7 +65,7 @@ public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P
|
||||
return delegate == null ? null : delegate.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
Object object = evaluator.evaluate(parameter.getSpelExpression().orElse(null));
|
||||
Object object = evaluator.evaluate(parameter.getSpelExpression());
|
||||
return object == null ? null : potentiallyConvertSpelValue(object, parameter);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,6 @@ public class PersistentEntityInformation<T, ID> extends AbstractEntityInformatio
|
||||
*/
|
||||
@Override
|
||||
public Class<ID> getIdType() {
|
||||
return (Class<ID>) persistentEntity.getIdProperty().map(PersistentProperty::getType).orElse(null);
|
||||
return (Class<ID>) persistentEntity.getRequiredIdProperty().getType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,18 +26,17 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.ProjectionInformation;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A representation of the type returned by a {@link QueryMethod}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.12
|
||||
@@ -49,7 +48,7 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReturnedType} for the given returned type, domain type and {@link ProjectionFactory}.
|
||||
*
|
||||
*
|
||||
* @param returnedType must not be {@literal null}.
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @param factory must not be {@literal null}.
|
||||
@@ -68,7 +67,7 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Returns the entity type.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public final Class<?> getDomainType() {
|
||||
@@ -77,7 +76,7 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Returns whether the given source object is an instance of the returned type.
|
||||
*
|
||||
*
|
||||
* @param source can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -87,21 +86,21 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Returns whether the type is projecting, i.e. not of the domain type.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean isProjecting();
|
||||
|
||||
/**
|
||||
* Returns the type of the individual objects to return.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract Class<?> getReturnedType();
|
||||
|
||||
/**
|
||||
* Returns whether the returned type will require custom construction.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean needsCustomConstruction();
|
||||
@@ -109,14 +108,14 @@ public abstract class ReturnedType {
|
||||
/**
|
||||
* Returns the type that the query execution is supposed to pass to the underlying infrastructure. {@literal null} is
|
||||
* returned to indicate a generic type (a map or tuple-like type) shall be used.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract Class<?> getTypeToRead();
|
||||
|
||||
/**
|
||||
* Returns the properties required to be used to populate the result.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract List<String> getInputProperties();
|
||||
@@ -134,7 +133,7 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReturnedInterface} from the given {@link ProjectionInformation} and domain type.
|
||||
*
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
* @param domainType must not be {@literal null}.
|
||||
*/
|
||||
@@ -148,7 +147,7 @@ public abstract class ReturnedType {
|
||||
this.domainType = domainType;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedTypeInformation#getReturnedType()
|
||||
*/
|
||||
@@ -165,7 +164,7 @@ public abstract class ReturnedType {
|
||||
return isProjecting() && information.isClosed();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedType#isProjecting()
|
||||
*/
|
||||
@@ -174,7 +173,7 @@ public abstract class ReturnedType {
|
||||
return !information.getType().isAssignableFrom(domainType);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedTypeInformation#getTypeToRead()
|
||||
*/
|
||||
@@ -183,7 +182,7 @@ public abstract class ReturnedType {
|
||||
return isProjecting() && information.isClosed() ? null : domainType;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedTypeInformation#getInputProperties()
|
||||
*/
|
||||
@@ -217,10 +216,9 @@ public abstract class ReturnedType {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReturnedClass} instance for the given returned type and domain type.
|
||||
*
|
||||
*
|
||||
* @param returnedType must not be {@literal null}.
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @param projectionInformation
|
||||
*/
|
||||
public ReturnedClass(Class<?> returnedType, Class<?> domainType) {
|
||||
|
||||
@@ -234,7 +232,7 @@ public abstract class ReturnedType {
|
||||
this.inputProperties = detectConstructorParameterNames(returnedType);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedTypeInformation#getReturnedType()
|
||||
*/
|
||||
@@ -251,7 +249,7 @@ public abstract class ReturnedType {
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedType#isProjecting()
|
||||
*/
|
||||
@@ -268,7 +266,7 @@ public abstract class ReturnedType {
|
||||
return isDto() && !inputProperties.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ResultFactory.ReturnedTypeInformation#getInputProperties()
|
||||
*/
|
||||
@@ -285,10 +283,19 @@ public abstract class ReturnedType {
|
||||
}
|
||||
|
||||
PreferredConstructorDiscoverer<?, ?> discoverer = new PreferredConstructorDiscoverer(type);
|
||||
PreferredConstructor<?, ?> constructor = discoverer.getConstructor();
|
||||
|
||||
return discoverer.getConstructor().map(it -> it.getParameters().stream()//
|
||||
.flatMap(parameter -> Optionals.toStream(parameter.getName()))//
|
||||
.collect(Collectors.toList())).orElseGet(Collections::emptyList);
|
||||
if (constructor == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> properties = new ArrayList<>(constructor.getConstructor().getParameterCount());
|
||||
|
||||
for (PreferredConstructor.Parameter<Object, ?> parameter : constructor.getParameters()) {
|
||||
properties.add(parameter.getName());
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private boolean isDto() {
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.data.util;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -28,8 +27,9 @@ import org.springframework.util.Assert;
|
||||
* Simple value type to delay the creation of an object using a {@link Supplier} returning the produced object for
|
||||
* subsequent lookups. Note, that no concurrency control is applied during the lookup of {@link #get()}, which means in
|
||||
* concurrent access scenarios, the provided {@link Supplier} can be called multiple times.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@@ -37,11 +37,11 @@ import org.springframework.util.Assert;
|
||||
public class Lazy<T> implements Supplier<T> {
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
private Optional<T> value;
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Lazy} to produce an object lazily.
|
||||
*
|
||||
*
|
||||
* @param <T> the type of which to produce an object of eventually.
|
||||
* @param supplier the {@link Supplier} to create the object lazily.
|
||||
* @return
|
||||
@@ -53,21 +53,21 @@ public class Lazy<T> implements Supplier<T> {
|
||||
/**
|
||||
* Returns the value created by the configured {@link Supplier}. Will return the calculated instance for subsequent
|
||||
* lookups.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public T get() {
|
||||
|
||||
if (value == null) {
|
||||
this.value = Optional.ofNullable(supplier.get());
|
||||
this.value = supplier.get();
|
||||
}
|
||||
|
||||
return value.orElse(null);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Lazy} with the given {@link Function} lazily applied to the current one.
|
||||
*
|
||||
*
|
||||
* @param function must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -80,7 +80,7 @@ public class Lazy<T> implements Supplier<T> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Lazy} with the given {@link Function} lazily applied to the current one.
|
||||
*
|
||||
*
|
||||
* @param function must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user