DATACMNS-1114 - Introduced usage of nullable annotations for API validation.
Marked all packages with Spring Frameworks @NonNullApi. Added Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fixed Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances. Removed null handling from converters for JodaTime and ThreeTenBP. Introduced factory methods Page.empty() and Page.empty(Pageable). Introduced default methods getRequiredGetter(), …Setter() and …Field() on PersistentProperty to allow non-nullable lookups of members. The same for TypeInformation.getrequiredActualType(), …SuperTypeInformation(). Tweaked PersistentPropertyCreator.addPropertiesForRemainingDescriptors() to filter unsuitable PropertyDescriptors before actually trying to create a Property instance from them as the new stronger nullability requirements would cause exceptions downstream. Lazy.get() now expects a non-null return value. Clients being able to cope with null need to call ….orElse(…). Original pull request: #232.
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -293,7 +293,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-rules</id>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Core annotations being used by Spring Data.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
@@ -226,7 +226,7 @@ public class AuditingHandler implements InitializingBean {
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (auditorAware == null) {
|
||||
if (!auditorAware.isPresent()) {
|
||||
LOGGER.debug("No AuditorAware set! Auditing will not be applied!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.convert.ThreeTenBackPortConverters;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -88,7 +89,7 @@ class DefaultAuditableBeanWrapperFactory implements AuditableBeanWrapperFactory
|
||||
|
||||
this.auditable = auditable;
|
||||
this.type = (Class<? extends TemporalAccessor>) ResolvableType.forClass(Auditable.class, auditable.getClass())
|
||||
.getGeneric(2).getRawClass();
|
||||
.getGeneric(2).resolve(TemporalAccessor.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -183,6 +184,7 @@ class DefaultAuditableBeanWrapperFactory implements AuditableBeanWrapperFactory
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
protected Object getDateValueToSet(TemporalAccessor value, Class<?> targetType, Object source) {
|
||||
|
||||
if (TemporalAccessor.class.equals(targetType)) {
|
||||
@@ -213,6 +215,7 @@ class DefaultAuditableBeanWrapperFactory implements AuditableBeanWrapperFactory
|
||||
* Returns the given object as {@link Calendar}.
|
||||
*
|
||||
* @param source can be {@literal null}.
|
||||
* @param target must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -299,7 +302,7 @@ class DefaultAuditableBeanWrapperFactory implements AuditableBeanWrapperFactory
|
||||
return getAsTemporalAccessor(metadata.getLastModifiedDateField().map(field -> {
|
||||
|
||||
Object value = org.springframework.util.ReflectionUtils.getField(field, target);
|
||||
return Optional.class.isInstance(value) ? ((Optional<?>) value).orElse(null) : value;
|
||||
return value instanceof Optional ? ((Optional<?>) value).orElse(null) : value;
|
||||
|
||||
}), TemporalAccessor.class);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.auditing.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -30,6 +31,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class AnnotationAuditingConfiguration implements AuditingConfiguration {
|
||||
|
||||
private static final String MISSING_ANNOTATION_ATTRIBUTES = "Couldn't find annotation attributes for %s in %s!";
|
||||
|
||||
private final AnnotationAttributes attributes;
|
||||
|
||||
/**
|
||||
@@ -44,7 +47,13 @@ public class AnnotationAuditingConfiguration implements AuditingConfiguration {
|
||||
Assert.notNull(metadata, "AnnotationMetadata must not be null!");
|
||||
Assert.notNull(annotation, "Annotation must not be null!");
|
||||
|
||||
this.attributes = new AnnotationAttributes(metadata.getAnnotationAttributes(annotation.getName()));
|
||||
Map<String, Object> attributesSource = metadata.getAnnotationAttributes(annotation.getName());
|
||||
|
||||
if (attributesSource == null) {
|
||||
throw new IllegalArgumentException(String.format(MISSING_ANNOTATION_ATTRIBUTES, annotation, metadata));
|
||||
}
|
||||
|
||||
this.attributes = new AnnotationAttributes(attributesSource);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.auditing.config;
|
||||
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -51,6 +53,7 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin
|
||||
*
|
||||
* @param mappingContextBeanName must not be {@literal null} or empty.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
public AuditingHandlerBeanDefinitionParser(String mappingContextBeanName) {
|
||||
|
||||
Assert.hasText(mappingContextBeanName, "MappingContext bean name must not be null!");
|
||||
@@ -70,6 +73,7 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return AuditingHandler.class;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Types to abstract authentication concepts.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.auditing.config;
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* General support for entity auditing.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.authentication;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -28,8 +29,7 @@ public class UserCredentials {
|
||||
|
||||
public static final UserCredentials NO_CREDENTIALS = new UserCredentials(null, null);
|
||||
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final @Nullable String username, password;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UserCredentials} instance from the given username and password. Empty {@link String}s provided
|
||||
@@ -38,7 +38,7 @@ public class UserCredentials {
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
public UserCredentials(String username, String password) {
|
||||
public UserCredentials(@Nullable String username, @Nullable String password) {
|
||||
this.username = StringUtils.hasText(username) ? username : null;
|
||||
this.password = StringUtils.hasText(password) ? password : null;
|
||||
}
|
||||
@@ -48,6 +48,7 @@ public class UserCredentials {
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
@@ -57,6 +58,7 @@ public class UserCredentials {
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
@Nullable
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
@@ -85,9 +87,12 @@ public class UserCredentials {
|
||||
*
|
||||
* @return the obfuscated password
|
||||
*/
|
||||
@Nullable
|
||||
public String getObfuscatedPassword() {
|
||||
|
||||
if (!hasPassword()) {
|
||||
String password = this.password;
|
||||
|
||||
if (password == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -125,7 +130,7 @@ public class UserCredentials {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Types to abstract authentication concepts.
|
||||
*/
|
||||
package org.springframework.data.authentication;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.authentication;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class to centralize common functionality that needs to be used in various places of the configuration
|
||||
* implementation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 2.0
|
||||
* @soundtrack Richard Spaven - The Self (feat. Jordan Rakei)
|
||||
*/
|
||||
public interface ConfigurationUtils {
|
||||
|
||||
/**
|
||||
* Returns the {@link ResourceLoader} from the given {@link XmlReaderContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException if no {@link ResourceLoader} can be obtained from the {@link XmlReaderContext}.
|
||||
*/
|
||||
public static ResourceLoader getRequiredResourceLoader(XmlReaderContext context) {
|
||||
|
||||
Assert.notNull(context, "XmlReaderContext must not be null!");
|
||||
|
||||
ResourceLoader resourceLoader = context.getResourceLoader();
|
||||
|
||||
if (resourceLoader == null) {
|
||||
throw new IllegalArgumentException("Could not obtain ResourceLoader from XmlReaderContext!");
|
||||
}
|
||||
|
||||
return resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ClassLoader} used by the given {@link XmlReaderContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException if no {@link ClassLoader} can be obtained from the given {@link XmlReaderContext}.
|
||||
*/
|
||||
public static ClassLoader getRequiredClassLoader(XmlReaderContext context) {
|
||||
return getRequiredClassLoader(getRequiredResourceLoader(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ClassLoader} used by the given {@link ResourceLoader}.
|
||||
*
|
||||
* @param resourceLoader must not be {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException if the given {@link ResourceLoader} does not expose a {@link ClassLoader}.
|
||||
*/
|
||||
public static ClassLoader getRequiredClassLoader(ResourceLoader resourceLoader) {
|
||||
|
||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
|
||||
|
||||
ClassLoader classLoader = resourceLoader.getClassLoader();
|
||||
|
||||
if (classLoader == null) {
|
||||
throw new IllegalArgumentException("Could not obtain ClassLoader from ResourceLoader!");
|
||||
}
|
||||
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bean class name of the given {@link BeanDefinition}.
|
||||
*
|
||||
* @param beanDefinition must not be {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException if the given {@link BeanDefinition} does not contain a bean class name.
|
||||
*/
|
||||
public static String getRequiredBeanClassName(BeanDefinition beanDefinition) {
|
||||
|
||||
Assert.notNull(beanDefinition, "BeanDefinition must not be null!");
|
||||
|
||||
String result = beanDefinition.getBeanClassName();
|
||||
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Could not obtain required bean class name from BeanDefinition!", beanDefinition));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -120,7 +121,7 @@ public abstract class ParsingUtils {
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, Object source) {
|
||||
public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, @Nullable Object source) {
|
||||
|
||||
Assert.notNull(builder, "Builder must not be null!");
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
@@ -55,7 +56,7 @@ public class TypeFilterParser {
|
||||
* @param readerContext must not be {@literal null}.
|
||||
*/
|
||||
public TypeFilterParser(XmlReaderContext readerContext) {
|
||||
this(readerContext, readerContext.getResourceLoader().getClassLoader());
|
||||
this(readerContext, ConfigurationUtils.getRequiredClassLoader(readerContext));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,13 +93,14 @@ public class TypeFilterParser {
|
||||
Node node = nodeList.item(i);
|
||||
Element childElement = type.getElement(node);
|
||||
|
||||
if (childElement != null) {
|
||||
if (childElement == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
filters.add(createTypeFilter(childElement, classLoader));
|
||||
} catch (RuntimeException e) {
|
||||
readerContext.error(e.getMessage(), readerContext.extractSource(element), e.getCause());
|
||||
}
|
||||
try {
|
||||
filters.add(createTypeFilter(childElement, classLoader));
|
||||
} catch (RuntimeException e) {
|
||||
readerContext.error(e.getMessage(), readerContext.extractSource(element), e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +226,7 @@ public class TypeFilterParser {
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
Element getElement(Node node) {
|
||||
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Basic support for creating custom Spring namespaces and JavaConfig.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.config;
|
||||
|
||||
@@ -38,6 +38,7 @@ 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;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -213,7 +214,7 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
private <P extends PersistentProperty<P>, T> Object[] extractInvocationArguments(
|
||||
PreferredConstructor<? extends T, P> constructor, ParameterValueProvider<P> provider) {
|
||||
@Nullable PreferredConstructor<? extends T, P> constructor, ParameterValueProvider<P> provider) {
|
||||
|
||||
if (provider == null || constructor == null || !constructor.hasParameters()) {
|
||||
return EMPTY_ARRAY;
|
||||
@@ -484,7 +485,7 @@ public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
*/
|
||||
private class ByteArrayClassLoader extends ClassLoader {
|
||||
|
||||
public ByteArrayClassLoader(ClassLoader parent) {
|
||||
public ByteArrayClassLoader(@Nullable ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -77,6 +79,7 @@ public class ConfigurableTypeInformationMapper implements TypeInformationMapper
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(org.springframework.data.mapping.Alias)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> resolveTypeFrom(Alias alias) {
|
||||
return aliasToType.get(alias);
|
||||
|
||||
@@ -561,8 +561,11 @@ public class CustomConversions {
|
||||
|
||||
} else if (converter instanceof GenericConverter) {
|
||||
|
||||
return Streamable.of(GenericConverter.class.cast(converter).getConvertibleTypes())//
|
||||
.map(it -> register(it, isReading, isWriting));
|
||||
Set<ConvertiblePair> convertibleTypes = GenericConverter.class.cast(converter).getConvertibleTypes();
|
||||
|
||||
return convertibleTypes == null //
|
||||
? Streamable.empty() //
|
||||
: Streamable.of(convertibleTypes).map(it -> register(it, isReading, isWriting));
|
||||
|
||||
} else if (converter instanceof ConverterFactory) {
|
||||
|
||||
@@ -580,7 +583,13 @@ public class CustomConversions {
|
||||
private Streamable<ConverterRegistration> getRegistrationFor(Object converter, Class<?> type, boolean isReading,
|
||||
boolean isWriting) {
|
||||
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), type);
|
||||
Class<? extends Object> converterType = converter.getClass();
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converterType, type);
|
||||
|
||||
if (arguments == null) {
|
||||
throw new IllegalStateException(String.format("Couldn't resolve type arguments for %s!", converterType));
|
||||
}
|
||||
|
||||
return Streamable.of(register(arguments[0], arguments[1], isReading, isWriting));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
@@ -35,6 +37,7 @@ import org.springframework.data.convert.ConverterBuilder.ConverterAware;
|
||||
import org.springframework.data.convert.ConverterBuilder.ReadingConverterBuilder;
|
||||
import org.springframework.data.convert.ConverterBuilder.WritingConverterBuilder;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Builder to easily set up (bi-directional) {@link Converter} instances for Spring Data type mapping using Lambdas. Use
|
||||
@@ -128,9 +131,10 @@ class DefaultConverterBuilder<S, T>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return function.apply((S) source);
|
||||
}
|
||||
|
||||
@@ -138,6 +142,7 @@ class DefaultConverterBuilder<S, T>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return Collections.singleton(convertiblePair);
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param additionalMappers must not be {@literal null}.
|
||||
*/
|
||||
public DefaultTypeMapper(TypeAliasAccessor<S> accessor,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||
@Nullable MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||
List<? extends TypeInformationMapper> additionalMappers) {
|
||||
|
||||
Assert.notNull(accessor, "Accessor must not be null!");
|
||||
@@ -109,6 +110,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeMapper#readType(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
public TypeInformation<?> readType(S source) {
|
||||
|
||||
Assert.notNull(source, "Source object must not be null!");
|
||||
@@ -123,6 +125,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param alias
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private TypeInformation<?> getFromCacheOrCreate(Alias alias) {
|
||||
return typeCache.computeIfAbsent(alias, getAlias).orElse(null);
|
||||
}
|
||||
@@ -153,7 +156,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
|
||||
ClassTypeInformation<?> targetType = ClassTypeInformation.from(documentsTargetType);
|
||||
|
||||
return (TypeInformation<? extends T>) (basicType != null ? basicType.specialize(targetType) : targetType);
|
||||
return (TypeInformation<? extends T>) basicType.specialize(targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,6 +166,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private Class<?> getDefaultedTypeToBeUsed(S source) {
|
||||
|
||||
TypeInformation<?> documentsTargetTypeInformation = readType(source);
|
||||
@@ -177,6 +181,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
|
||||
* @param source will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
protected TypeInformation<?> getFallbackTypeFor(S source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalDateTime;
|
||||
@@ -72,9 +74,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public java.time.LocalDateTime convert(LocalDateTime source) {
|
||||
return source == null ? null : java.time.LocalDateTime.ofInstant(source.toDate().toInstant(), ZoneId.of("UTC"));
|
||||
return java.time.LocalDateTime.ofInstant(source.toDate().toInstant(), ZoneId.of("UTC"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +85,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDate source) {
|
||||
return source == null ? null : source.toDate();
|
||||
return source.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +96,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDateTime source) {
|
||||
return source == null ? null : source.toDate();
|
||||
return source.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +107,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(DateTime source) {
|
||||
return source == null ? null : source.toDate();
|
||||
return source.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +118,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDate convert(Date source) {
|
||||
return source == null ? null : new LocalDate(source.getTime());
|
||||
return new LocalDate(source.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +129,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDateTime convert(Date source) {
|
||||
return source == null ? null : new LocalDateTime(source.getTime());
|
||||
return new LocalDateTime(source.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +140,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public DateTime convert(Date source) {
|
||||
return source == null ? null : new DateTime(source.getTime());
|
||||
return new DateTime(source.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,15 +151,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDateTime convert(java.time.LocalDateTime source) {
|
||||
return source == null ? null
|
||||
: LocalDateTime.fromDateFields(
|
||||
org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
return LocalDateTime.fromDateFields(Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,15 +162,10 @@ public abstract class JodaTimeConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public DateTime convert(java.time.LocalDateTime source) {
|
||||
return source == null ? null
|
||||
: new DateTime(
|
||||
org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
return new DateTime(Jsr310Converters.LocalDateTimeToDateConverter.INSTANCE.convert(source));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -92,9 +94,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDateTime convert(Date source) {
|
||||
return source == null ? null : ofInstant(source.toInstant(), systemDefault());
|
||||
return ofInstant(source.toInstant(), systemDefault());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +105,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDateTime source) {
|
||||
return source == null ? null : Date.from(source.atZone(systemDefault()).toInstant());
|
||||
return Date.from(source.atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +116,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDate convert(Date source) {
|
||||
return source == null ? null : ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalDate();
|
||||
return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +127,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDate source) {
|
||||
return source == null ? null : Date.from(source.atStartOfDay(systemDefault()).toInstant());
|
||||
return Date.from(source.atStartOfDay(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,9 +138,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalTime convert(Date source) {
|
||||
return source == null ? null : ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalTime();
|
||||
return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalTime();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +149,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalTime source) {
|
||||
return source == null ? null : Date.from(source.atDate(LocalDate.now()).atZone(systemDefault()).toInstant());
|
||||
return Date.from(source.atDate(LocalDate.now()).atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,9 +160,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Instant convert(Date source) {
|
||||
return source == null ? null : source.toInstant();
|
||||
return source.toInstant();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,9 +171,10 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(Instant source) {
|
||||
return source == null ? null : Date.from(source.atZone(systemDefault()).toInstant());
|
||||
return Date.from(source.atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +183,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String convert(ZoneId source) {
|
||||
return source.toString();
|
||||
@@ -184,6 +195,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ZoneId convert(String source) {
|
||||
return ZoneId.of(source);
|
||||
@@ -195,6 +207,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String convert(Duration duration) {
|
||||
return duration.toString();
|
||||
@@ -206,6 +219,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Duration convert(String s) {
|
||||
return Duration.parse(s);
|
||||
@@ -217,6 +231,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String convert(Period period) {
|
||||
return period.toString();
|
||||
@@ -228,6 +243,7 @@ public abstract class Jsr310Converters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Period convert(String s) {
|
||||
return Period.parse(s);
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -115,6 +116,7 @@ public class MappingContextTypeInformationMapper implements TypeInformationMappe
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.TypeInformationMapper#resolveTypeFrom(java.util.Optional)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> resolveTypeFrom(Alias alias) {
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,7 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
|
||||
* @return the type to be used for the given {@link String} representation or {@literal null} if nothing found or the
|
||||
* class cannot be loaded.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeInformation<?> resolveTypeFrom(Alias alias) {
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.threeten.bp.Instant;
|
||||
@@ -95,12 +97,13 @@ public abstract class ThreeTenBackPortConverters {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public java.time.LocalDateTime convert(LocalDateTime source) {
|
||||
|
||||
Date date = toDate(source.atZone(ZoneId.systemDefault()).toInstant());
|
||||
|
||||
return source == null ? null : Jsr310Converters.DateToLocalDateTimeConverter.INSTANCE.convert(date);
|
||||
return Jsr310Converters.DateToLocalDateTimeConverter.INSTANCE.convert(date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +111,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDateTime convert(Date source) {
|
||||
|
||||
return source == null ? null : ofInstant(toInstant(source), systemDefault());
|
||||
return ofInstant(toInstant(source), systemDefault());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +122,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDateTime source) {
|
||||
return source == null ? null : toDate(source.atZone(systemDefault()).toInstant());
|
||||
return toDate(source.atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +133,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalDate convert(Date source) {
|
||||
return source == null ? null : ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalDate();
|
||||
return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +144,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalDate source) {
|
||||
return source == null ? null : toDate(source.atStartOfDay(systemDefault()).toInstant());
|
||||
return toDate(source.atStartOfDay(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +155,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public LocalTime convert(Date source) {
|
||||
return source == null ? null : ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalTime();
|
||||
return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalTime();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,9 +166,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(LocalTime source) {
|
||||
return source == null ? null : toDate(source.atDate(LocalDate.now()).atZone(systemDefault()).toInstant());
|
||||
return toDate(source.atDate(LocalDate.now()).atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +177,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Instant convert(Date source) {
|
||||
return source == null ? null : toInstant(source);
|
||||
return toInstant(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,9 +188,10 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Date convert(Instant source) {
|
||||
return source == null ? null : toDate(source.atZone(systemDefault()).toInstant());
|
||||
return toDate(source.atZone(systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +200,7 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String convert(ZoneId source) {
|
||||
return source.toString();
|
||||
@@ -201,6 +212,7 @@ public abstract class ThreeTenBackPortConverters {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ZoneId convert(String source) {
|
||||
return ZoneId.of(source);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
@@ -28,15 +30,16 @@ public interface TypeInformationMapper {
|
||||
/**
|
||||
* Returns the actual {@link TypeInformation} to be used for the given alias.
|
||||
*
|
||||
* @param alias can be {@literal null}.
|
||||
* @param alias must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
TypeInformation<?> resolveTypeFrom(Alias alias);
|
||||
|
||||
/**
|
||||
* Returns the alias to be used for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param type
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Alias createAliasFor(TypeInformation<?> type);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface to define strategies how to store type information in a store specific sink or source.
|
||||
@@ -30,13 +31,14 @@ public interface TypeMapper<S> {
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
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
|
||||
* @param defaultType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> TypeInformation<? extends T> readType(S source, TypeInformation<T> defaultType);
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
*
|
||||
* @see org.springframework.data.convert.EntityConverter
|
||||
*/
|
||||
package org.springframework.data.convert;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.convert;
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.crossstore;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
@@ -27,12 +29,14 @@ import org.springframework.core.convert.ConversionService;
|
||||
*/
|
||||
public interface ChangeSet {
|
||||
|
||||
@Nullable
|
||||
<T> T get(String key, Class<T> requiredClass, ConversionService cs);
|
||||
|
||||
void set(String key, Object o);
|
||||
|
||||
Map<String, Object> getValues();
|
||||
|
||||
@Nullable
|
||||
Object removeProperty(String k);
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Simple ChangeSet implementation backed by a HashMap.
|
||||
@@ -52,12 +53,21 @@ public class HashMapChangeSet implements ChangeSet {
|
||||
return Collections.unmodifiableMap(values);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object removeProperty(String k) {
|
||||
return this.values.remove(k);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T get(String key, Class<T> requiredClass, ConversionService conversionService) {
|
||||
return conversionService.convert(values.get(key), requiredClass);
|
||||
|
||||
Object value = values.get(key);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return conversionService.convert(value, requiredClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Support for cross-store persistence.
|
||||
*/
|
||||
package org.springframework.data.crossstore;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.crossstore;
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract Java Bean implementation of {@code Pageable}.
|
||||
*
|
||||
@@ -131,7 +133,7 @@ public abstract class AbstractPageRequest implements Pageable, Serializable {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -171,7 +172,7 @@ abstract class Chunk<T> implements Slice<T>, Serializable {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -201,9 +202,7 @@ public class ExampleMatcher {
|
||||
propertySpecifier = propertySpecifier.withStringMatcher(genericPropertyMatcher.stringMatcher);
|
||||
}
|
||||
|
||||
if (genericPropertyMatcher.valueTransformer != null) {
|
||||
propertySpecifier = propertySpecifier.withValueTransformer(genericPropertyMatcher.valueTransformer);
|
||||
}
|
||||
propertySpecifier = propertySpecifier.withValueTransformer(genericPropertyMatcher.valueTransformer);
|
||||
|
||||
propertySpecifiers.add(propertySpecifier);
|
||||
|
||||
@@ -394,8 +393,8 @@ public class ExampleMatcher {
|
||||
@EqualsAndHashCode
|
||||
public static class GenericPropertyMatcher {
|
||||
|
||||
StringMatcher stringMatcher = null;
|
||||
Boolean ignoreCase = null;
|
||||
@Nullable StringMatcher stringMatcher = null;
|
||||
@Nullable Boolean ignoreCase = null;
|
||||
PropertyValueTransformer valueTransformer = NoOpPropertyValueTransformer.INSTANCE;
|
||||
|
||||
/**
|
||||
@@ -697,6 +696,7 @@ public class ExampleMatcher {
|
||||
* @see java.util.function.Function#apply(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public Optional<Object> apply(Optional<Object> source) {
|
||||
return source;
|
||||
}
|
||||
@@ -715,8 +715,8 @@ public class ExampleMatcher {
|
||||
public static class PropertySpecifier {
|
||||
|
||||
String path;
|
||||
StringMatcher stringMatcher;
|
||||
Boolean ignoreCase;
|
||||
@Nullable StringMatcher stringMatcher;
|
||||
@Nullable Boolean ignoreCase;
|
||||
PropertyValueTransformer valueTransformer;
|
||||
|
||||
/**
|
||||
@@ -785,6 +785,7 @@ public class ExampleMatcher {
|
||||
*
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
public StringMatcher getStringMatcher() {
|
||||
return stringMatcher;
|
||||
}
|
||||
@@ -792,6 +793,7 @@ public class ExampleMatcher {
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
@Nullable
|
||||
public Boolean getIgnoreCase() {
|
||||
return ignoreCase;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,27 @@ import java.util.function.Function;
|
||||
*/
|
||||
public interface Page<T> extends Slice<T> {
|
||||
|
||||
/**
|
||||
* Creates a new empty {@link Page}.
|
||||
*
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
static <T> Page<T> empty() {
|
||||
return empty(Pageable.unpaged());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty {@link Page} for the given {@link Pageable}.
|
||||
*
|
||||
* @param pageable must not be {@literal null}.
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
static <T> Page<T> empty(Pageable pageable) {
|
||||
return new PageImpl<>(Collections.emptyList(), pageable, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of total pages.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.domain;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Basic {@code Page} implementation.
|
||||
*
|
||||
@@ -127,7 +129,7 @@ public class PageImpl<T> extends Chunk<T> implements Page<T> {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Basic Java Bean implementation of {@code Pageable}.
|
||||
@@ -145,7 +146,7 @@ public class PageRequest extends AbstractPageRequest {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.domain;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link Slice}.
|
||||
*
|
||||
@@ -95,7 +97,7 @@ public class SliceImpl<T> extends Chunk<T> {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -212,9 +213,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
*/
|
||||
public Sort and(Sort sort) {
|
||||
|
||||
if (sort == null) {
|
||||
return this;
|
||||
}
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
ArrayList<Order> these = new ArrayList<>(this.orders);
|
||||
|
||||
@@ -231,6 +230,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Order getOrderFor(String property) {
|
||||
|
||||
for (Order order : this) {
|
||||
@@ -255,7 +255,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
@@ -400,6 +400,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
|
||||
private static final long serialVersionUID = 1522511010900108987L;
|
||||
private static final boolean DEFAULT_IGNORE_CASE = false;
|
||||
private static final NullHandling DEFAULT_NULL_HANDLING = NullHandling.NATIVE;
|
||||
|
||||
private final Direction direction;
|
||||
private final String property;
|
||||
@@ -414,7 +415,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @param property must not be {@literal null} or empty.
|
||||
*/
|
||||
public Order(Direction direction, String property) {
|
||||
this(direction, property, DEFAULT_IGNORE_CASE, null);
|
||||
this(direction, property, DEFAULT_IGNORE_CASE, DEFAULT_NULL_HANDLING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -423,7 +424,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
*
|
||||
* @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
|
||||
* @param property must not be {@literal null} or empty.
|
||||
* @param nullHandling can be {@literal null}, will default to {@link NullHandling#NATIVE}.
|
||||
* @param nullHandling must not be {@literal null}.
|
||||
*/
|
||||
public Order(Direction direction, String property, NullHandling nullHandlingHint) {
|
||||
this(direction, property, DEFAULT_IGNORE_CASE, nullHandlingHint);
|
||||
@@ -460,7 +461,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @since 2.0
|
||||
*/
|
||||
public static Order asc(String property) {
|
||||
return new Order(Direction.ASC, property, null);
|
||||
return new Order(Direction.ASC, property, DEFAULT_NULL_HANDLING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -471,7 +472,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @since 2.0
|
||||
*/
|
||||
public static Order desc(String property) {
|
||||
return new Order(Direction.DESC, property, null);
|
||||
return new Order(Direction.DESC, property, DEFAULT_NULL_HANDLING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,7 +482,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}
|
||||
* @param property must not be {@literal null} or empty.
|
||||
* @param ignoreCase true if sorting should be case insensitive. false if sorting should be case sensitive.
|
||||
* @param nullHandling can be {@literal null}, will default to {@link NullHandling#NATIVE}.
|
||||
* @param nullHandling must not be {@literal null}.
|
||||
* @since 1.7
|
||||
*/
|
||||
private Order(Direction direction, String property, boolean ignoreCase, NullHandling nullHandling) {
|
||||
@@ -493,7 +494,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
this.direction = direction == null ? DEFAULT_DIRECTION : direction;
|
||||
this.property = property;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.nullHandling = nullHandling == null ? NullHandling.NATIVE : nullHandling;
|
||||
this.nullHandling = nullHandling;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +656,7 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -17,8 +17,10 @@ package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* XmlAdapter to convert {@link Order} instances into {@link OrderDto}s and vice versa.
|
||||
@@ -33,8 +35,9 @@ public class OrderAdapter extends XmlAdapter<OrderDto, Order> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public OrderDto marshal(Order order) {
|
||||
public OrderDto marshal(@Nullable Order order) {
|
||||
|
||||
if (order == null) {
|
||||
return null;
|
||||
@@ -50,8 +53,21 @@ public class OrderAdapter extends XmlAdapter<OrderDto, Order> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Order unmarshal(OrderDto source) {
|
||||
return source == null ? null : new Order(source.direction, source.property);
|
||||
public Order unmarshal(@Nullable OrderDto source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Direction direction = source.direction;
|
||||
String property = source.property;
|
||||
|
||||
if (direction == null || property == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Order(direction, property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageDto;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Page} instances into {@link PageDto} instances and vice versa.
|
||||
@@ -35,8 +36,9 @@ public class PageAdapter extends XmlAdapter<PageDto, Page<Object>> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public PageDto marshal(Page<Object> source) {
|
||||
public PageDto marshal(@Nullable Page<Object> source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
@@ -53,8 +55,9 @@ public class PageAdapter extends XmlAdapter<PageDto, Page<Object>> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Page<Object> unmarshal(PageDto v) {
|
||||
public Page<Object> unmarshal(@Nullable PageDto v) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,14 @@ package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageRequestDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Pageable} instances int a {@link PageRequestDto} and vice versa.
|
||||
@@ -37,12 +38,17 @@ class PageableAdapter extends XmlAdapter<PageRequestDto, Pageable> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public PageRequestDto marshal(Pageable request) {
|
||||
public PageRequestDto marshal(@Nullable Pageable request) {
|
||||
|
||||
SortDto sortDto = SortAdapter.INSTANCE.marshal(request.getSort());
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PageRequestDto dto = new PageRequestDto();
|
||||
|
||||
SortDto sortDto = SortAdapter.INSTANCE.marshal(request.getSort());
|
||||
dto.orders = sortDto == null ? Collections.emptyList() : sortDto.orders;
|
||||
dto.page = request.getPageNumber();
|
||||
dto.size = request.getPageSize();
|
||||
@@ -54,8 +60,13 @@ class PageableAdapter extends XmlAdapter<PageRequestDto, Pageable> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public Pageable unmarshal(PageRequestDto v) {
|
||||
public Pageable unmarshal(@Nullable PageRequestDto v) {
|
||||
|
||||
if (v == null) {
|
||||
return Pageable.unpaged();
|
||||
}
|
||||
|
||||
if (v.orders.isEmpty()) {
|
||||
return PageRequest.of(v.page, v.size);
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Sort} instances into {@link SortDto} instances and vice versa.
|
||||
@@ -33,8 +35,9 @@ public class SortAdapter extends XmlAdapter<SortDto, Sort> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public SortDto marshal(Sort source) {
|
||||
public SortDto marshal(@Nullable Sort source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
@@ -50,8 +53,9 @@ public class SortAdapter extends XmlAdapter<SortDto, Sort> {
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public Sort unmarshal(SortDto source) {
|
||||
public Sort unmarshal(@Nullable SortDto source) {
|
||||
return source == null ? Sort.unsorted() : Sort.by(SpringDataJaxb.unmarshal(source.orders, OrderAdapter.INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -84,8 +85,8 @@ public abstract class SpringDataJaxb {
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class OrderDto {
|
||||
|
||||
@XmlAttribute String property;
|
||||
@XmlAttribute Direction direction;
|
||||
@Nullable @XmlAttribute String property;
|
||||
@Nullable @XmlAttribute Direction direction;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,7 @@ public abstract class SpringDataJaxb {
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class PageDto extends ResourceSupport {
|
||||
|
||||
@XmlAnyElement @XmlElementWrapper(name = "content") List<Object> content;
|
||||
@Nullable @XmlAnyElement @XmlElementWrapper(name = "content") List<Object> content;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +137,7 @@ public abstract class SpringDataJaxb {
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T, S> List<S> marshal(Iterable<T> source, XmlAdapter<S, T> adapter) {
|
||||
public static <T, S> List<S> marshal(@Nullable Iterable<T> source, XmlAdapter<S, T> adapter) {
|
||||
|
||||
Assert.notNull(adapter, "Adapter must not be null!");
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
/**
|
||||
* Central domain abstractions especially to be used in combination with the {@link org.springframework.data.repository.Repository} abstraction.
|
||||
* Central domain abstractions especially to be used in combination with the
|
||||
* {@link org.springframework.data.repository.Repository} abstraction.
|
||||
*
|
||||
* @see org.springframework.data.repository.Repository
|
||||
*/
|
||||
@XmlSchema(xmlns = { @XmlNs(prefix = "sd", namespaceURI = org.springframework.data.domain.jaxb.SpringDataJaxb.NAMESPACE) })
|
||||
@XmlSchema(
|
||||
xmlns = { @XmlNs(prefix = "sd", namespaceURI = org.springframework.data.domain.jaxb.SpringDataJaxb.NAMESPACE) })
|
||||
@XmlJavaTypeAdapters({
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageableAdapter.class, type = Pageable.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.SortAdapter.class, type = Sort.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageAdapter.class, type = Page.class) })
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.XmlNs;
|
||||
@@ -18,4 +21,3 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Central domain abstractions especially to be used in combination with the {@link org.springframework.data.repository.Repository} abstraction.
|
||||
* Central domain abstractions especially to be used in combination with the
|
||||
* {@link org.springframework.data.repository.Repository} abstraction.
|
||||
*
|
||||
* @see org.springframework.data.repository.Repository
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.domain;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -109,7 +110,7 @@ public class Box implements Shape {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -26,6 +28,7 @@ import org.springframework.util.Assert;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.8
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class Circle implements Shape {
|
||||
|
||||
private static final long serialVersionUID = 5215611530535947924L;
|
||||
@@ -98,39 +101,4 @@ public class Circle implements Shape {
|
||||
public String toString() {
|
||||
return String.format("Circle: [center=%s, radius=%s]", center, radius);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Circle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Circle that = (Circle) obj;
|
||||
|
||||
return this.center.equals(that.center) && this.radius.equals(that.radius);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * center.hashCode();
|
||||
result += 31 * radius.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -27,11 +31,19 @@ import org.springframework.util.Assert;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.8
|
||||
*/
|
||||
@Value
|
||||
public class Distance implements Serializable, Comparable<Distance> {
|
||||
|
||||
private static final long serialVersionUID = 2460886201934027744L;
|
||||
|
||||
/**
|
||||
* The distance value in the current {@link Metric}.
|
||||
*/
|
||||
private final double value;
|
||||
|
||||
/**
|
||||
* The {@link Metric} of the {@link Distance}.
|
||||
*/
|
||||
private final Metric metric;
|
||||
|
||||
/**
|
||||
@@ -47,12 +59,14 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
* Creates a new {@link Distance} with the given {@link Metric}.
|
||||
*
|
||||
* @param value
|
||||
* @param metric can be {@literal null}.
|
||||
* @param metric must not be {@literal null}.
|
||||
*/
|
||||
public Distance(double value, Metric metric) {
|
||||
|
||||
Assert.notNull(metric, "Metric must not be null!");
|
||||
|
||||
this.value = value;
|
||||
this.metric = metric == null ? Metrics.NEUTRAL : metric;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +77,7 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public static Range<Distance> between(Distance min, Distance max) {
|
||||
return new Range<>(min, max);
|
||||
return Range.from(Bound.inclusive(min)).to(Bound.inclusive(max));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,15 +93,6 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
return between(new Distance(minValue, minMetric), new Distance(maxValue, maxMetric));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance value in the current {@link Metric}.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized value regarding the underlying {@link Metric}.
|
||||
*
|
||||
@@ -97,15 +102,6 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
return value / metric.getMultiplier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Metric} of the {@link Distance}.
|
||||
*
|
||||
* @return the metric
|
||||
*/
|
||||
public Metric getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} representation of the unit the distance is in.
|
||||
*
|
||||
@@ -160,6 +156,7 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
public Distance in(Metric metric) {
|
||||
|
||||
Assert.notNull(metric, "Metric must not be null!");
|
||||
|
||||
return this.metric.equals(metric) ? this : new Distance(getNormalizedValue() * metric.getMultiplier(), metric);
|
||||
}
|
||||
|
||||
@@ -168,49 +165,19 @@ public class Distance implements Serializable, Comparable<Distance> {
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Distance o) {
|
||||
public int compareTo(@Nullable Distance that) {
|
||||
|
||||
double difference = this.getNormalizedValue() - o.getNormalizedValue();
|
||||
if (that == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
double difference = this.getNormalizedValue() - that.getNormalizedValue();
|
||||
|
||||
return difference == 0 ? 0 : difference > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Distance)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Distance that = (Distance) obj;
|
||||
|
||||
return this.value == that.value && this.metric.equals(that.metric);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * Double.doubleToLongBits(value);
|
||||
result += 31 * metric.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -31,7 +34,11 @@ import org.springframework.util.ObjectUtils;
|
||||
public class GeoPage<T> extends PageImpl<GeoResult<T>> {
|
||||
|
||||
private static final long serialVersionUID = -5655267379242128600L;
|
||||
private final Distance averageDistance;
|
||||
|
||||
/**
|
||||
* The average distance of the underlying results.
|
||||
*/
|
||||
private final @Getter Distance averageDistance;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
|
||||
@@ -59,21 +66,12 @@ public class GeoPage<T> extends PageImpl<GeoResult<T>> {
|
||||
this.averageDistance = results.getAverageDistance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average distance of the underlying results.
|
||||
*
|
||||
* @return the averageDistance
|
||||
*/
|
||||
public Distance getAverageDistance() {
|
||||
return averageDistance;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.domain.PageImpl#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Value object capturing some arbitrary object plus a distance.
|
||||
@@ -26,80 +27,13 @@ import org.springframework.util.Assert;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.8
|
||||
*/
|
||||
@Value
|
||||
public class GeoResult<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1637452570977581370L;
|
||||
|
||||
private final T content;
|
||||
private final Distance distance;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoResult} for the given content and distance.
|
||||
*
|
||||
* @param content must not be {@literal null}.
|
||||
* @param distance must not be {@literal null}.
|
||||
*/
|
||||
public GeoResult(T content, Distance distance) {
|
||||
|
||||
Assert.notNull(content, "Content must not be null!");
|
||||
Assert.notNull(distance, "Distance must not be null!");
|
||||
|
||||
this.content = content;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual content object.
|
||||
*
|
||||
* @return the content
|
||||
*/
|
||||
public T getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance the actual content object has from the origin.
|
||||
*
|
||||
* @return the distance
|
||||
*/
|
||||
public Distance getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoResult)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeoResult<?> that = (GeoResult<?>) obj;
|
||||
|
||||
return this.content.equals(that.content) && this.distance.equals(that.distance);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * distance.hashCode();
|
||||
result += 31 * content.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
@NonNull T content;
|
||||
@NonNull Distance distance;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@@ -31,6 +33,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.8
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8347363491300219485L;
|
||||
@@ -45,7 +48,7 @@ public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
* @param results must not be {@literal null}.
|
||||
*/
|
||||
public GeoResults(List<? extends GeoResult<T>> results) {
|
||||
this(results, (Metric) null);
|
||||
this(results, Metrics.NEUTRAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,12 +66,13 @@ public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
* Creates a new {@link GeoResults} instance from the given {@link GeoResult}s and average distance.
|
||||
*
|
||||
* @param results must not be {@literal null}.
|
||||
* @param averageDistance can be {@literal null}.
|
||||
* @param averageDistance must not be {@literal null}.
|
||||
*/
|
||||
@PersistenceConstructor
|
||||
public GeoResults(List<? extends GeoResult<T>> results, Distance averageDistance) {
|
||||
|
||||
Assert.notNull(results, "Results must not be null!");
|
||||
Assert.notNull(averageDistance, "Average Distance must not be null!");
|
||||
|
||||
this.results = results;
|
||||
this.averageDistance = averageDistance;
|
||||
@@ -101,41 +105,6 @@ public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
return (Iterator<GeoResult<T>>) results.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoResults)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeoResults<?> that = (GeoResults<?>) obj;
|
||||
|
||||
return this.results.equals(that.results) && this.averageDistance.equals(that.averageDistance);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * results.hashCode();
|
||||
result += 31 * averageDistance.hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
@@ -148,16 +117,17 @@ public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
|
||||
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
|
||||
|
||||
Assert.notNull(results, "Results must not be null!");
|
||||
Assert.notNull(metric, "Metric must not be null!");
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return new Distance(0, metric);
|
||||
}
|
||||
|
||||
double averageDistance = 0;
|
||||
double averageDistance = results.stream()//
|
||||
.mapToDouble(it -> it.getDistance().getValue())//
|
||||
.average().orElse(0);
|
||||
|
||||
for (GeoResult<?> result : results) {
|
||||
averageDistance += result.getDistance().getValue();
|
||||
}
|
||||
|
||||
return new Distance(averageDistance / results.size(), metric);
|
||||
return new Distance(averageDistance, metric);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ public class Point implements Serializable {
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -32,6 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.8
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
public class Polygon implements Iterable<Point>, Shape {
|
||||
|
||||
private static final long serialVersionUID = -2705040068154648988L;
|
||||
@@ -98,35 +101,6 @@ public class Polygon implements Iterable<Point>, Shape {
|
||||
return this.points.iterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Polygon)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Polygon that = (Polygon) obj;
|
||||
|
||||
return this.points.equals(that.points);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return points.hashCode();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -60,6 +61,7 @@ public enum DistanceFormatter implements Converter<String, Distance>, Formatter<
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public final Distance convert(String source) {
|
||||
return source == null ? null : doConvert(source.trim().toLowerCase(Locale.US));
|
||||
@@ -80,7 +82,7 @@ public enum DistanceFormatter implements Converter<String, Distance>, Formatter<
|
||||
*/
|
||||
@Override
|
||||
public Distance parse(String text, Locale locale) throws ParseException {
|
||||
return !StringUtils.hasText(text) ? null : doConvert(text.trim().toLowerCase(locale));
|
||||
return doConvert(text.trim().toLowerCase(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,11 +18,12 @@ package org.springframework.data.geo.format;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Converter to parse two comma-separated doubles into a {@link Point}.
|
||||
@@ -41,6 +42,7 @@ public enum PointFormatter implements Converter<String, Point>, Formatter<Point>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public Point convert(String source) {
|
||||
|
||||
@@ -77,6 +79,6 @@ public enum PointFormatter implements Converter<String, Point>, Formatter<Point>
|
||||
*/
|
||||
@Override
|
||||
public Point parse(String text, Locale locale) throws ParseException {
|
||||
return !StringUtils.hasText(text) ? null : convert(text);
|
||||
return convert(text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Formatters for geo-spatial types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.geo.format;
|
||||
@@ -5,4 +5,5 @@
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.geo;
|
||||
|
||||
@@ -25,6 +25,8 @@ import lombok.Value;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Wrapper to contain {@link RevisionMetadata} as well as the revisioned entity.
|
||||
*
|
||||
@@ -97,7 +99,12 @@ public final class Revision<N extends Number & Comparable<N>, T> implements Comp
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
public int compareTo(Revision<N, ?> that) {
|
||||
public int compareTo(@Nullable Revision<N, ?> that) {
|
||||
|
||||
if (that == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return mapIfAllPresent(getRevisionNumber(), that.getRevisionNumber(), //
|
||||
(left, right) -> left.compareTo(right)).orElse(-1);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.history;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A dedicated {@link Sort} implementation that allows the definition of the ordering of revisions independently of the
|
||||
@@ -66,14 +67,12 @@ public class RevisionSort extends Sort {
|
||||
* Returns in which direction to sort revisions for the given {@link Sort} instance. Defaults to
|
||||
* {@link Direction#ASC}.
|
||||
*
|
||||
* @param sort can be {@literal null}.
|
||||
* @param sort must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Direction getRevisionDirection(Sort sort) {
|
||||
|
||||
if (sort == null) {
|
||||
return Direction.ASC;
|
||||
}
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
Order order = sort.getOrderFor(PROPERTY);
|
||||
return order == null ? Direction.ASC : order.getDirection();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Basic interfaces and value objects for historiography API.
|
||||
* Basic interfaces and value objects for histography API.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.history;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -41,6 +42,7 @@ public class Alias {
|
||||
/**
|
||||
* Common instance for {@code empty()}.
|
||||
*/
|
||||
@SuppressWarnings("null") //
|
||||
public static final Alias NONE = new Alias(null);
|
||||
|
||||
private final Object value;
|
||||
@@ -65,7 +67,7 @@ public class Alias {
|
||||
* @param alias may be {@literal null}.
|
||||
* @return the {@link Alias} for {@code alias} or {@link #empty()} if the given alias was {@literal null}.
|
||||
*/
|
||||
public static Alias ofNullable(Object alias) {
|
||||
public static Alias ofNullable(@Nullable Object alias) {
|
||||
return alias == null ? NONE : new Alias(alias);
|
||||
}
|
||||
|
||||
@@ -124,6 +126,7 @@ public class Alias {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T mapTyped(Class<T> type) {
|
||||
|
||||
@@ -132,7 +135,8 @@ public class Alias {
|
||||
return isPresent() && type.isInstance(value) ? (T) value : null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface for a component allowing the access of identifier values.
|
||||
*
|
||||
@@ -29,6 +31,7 @@ public interface IdentifierAccessor {
|
||||
*
|
||||
* @return the identifier of the underlying instance.
|
||||
*/
|
||||
@Nullable
|
||||
Object getIdentifier();
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,21 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public MappingException(String s) {
|
||||
public MappingException(@Nullable String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public MappingException(String s, Throwable throwable) {
|
||||
public MappingException(@Nullable String s, @Nullable Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Iterator;
|
||||
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a persistent entity.
|
||||
@@ -47,6 +48,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* 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.
|
||||
*/
|
||||
@Nullable
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
@@ -81,6 +83,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
*
|
||||
* @return the id property of the {@link PersistentEntity}.
|
||||
*/
|
||||
@Nullable
|
||||
P getIdProperty();
|
||||
|
||||
/**
|
||||
@@ -107,6 +110,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
*
|
||||
* @return the version property of the {@link PersistentEntity}.
|
||||
*/
|
||||
@Nullable
|
||||
P getVersionProperty();
|
||||
|
||||
/**
|
||||
@@ -134,6 +138,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* @param name The name of the property. Can be {@literal null}.
|
||||
* @return the {@link PersistentProperty} or {@literal null} if it doesn't exist.
|
||||
*/
|
||||
@Nullable
|
||||
P getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
@@ -161,6 +166,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* @return {@literal null} if no property found with given annotation type.
|
||||
* @since 1.8
|
||||
*/
|
||||
@Nullable
|
||||
default P getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Iterator<P> it = getPersistentProperties(annotationType).iterator();
|
||||
@@ -240,6 +246,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* @return {@literal null} if not found.
|
||||
* @since 1.8
|
||||
*/
|
||||
@Nullable
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Graeme Rocher
|
||||
@@ -75,26 +76,64 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return the getter method to access the property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
Method getGetter();
|
||||
|
||||
default Method getRequiredGetter() {
|
||||
|
||||
Method getter = getGetter();
|
||||
|
||||
if (getter == null) {
|
||||
throw new IllegalArgumentException("No getter available for this persistent property!");
|
||||
}
|
||||
|
||||
return getter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
@Nullable
|
||||
Method getSetter();
|
||||
|
||||
default Method getRequiredSetter() {
|
||||
|
||||
Method setter = getSetter();
|
||||
|
||||
if (setter == null) {
|
||||
throw new IllegalArgumentException("No setter available for this persistent property!");
|
||||
}
|
||||
|
||||
return setter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Field getField();
|
||||
|
||||
default Field getRequiredField() {
|
||||
|
||||
Field field = getField();
|
||||
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("No field backing this persistent property!");
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if no expression defined.
|
||||
*/
|
||||
@Nullable
|
||||
String getSpelExpression();
|
||||
|
||||
/**
|
||||
* @return {@literal null} if property is not part of an {@link Association}.
|
||||
*/
|
||||
@Nullable
|
||||
Association<P> getAssociation();
|
||||
|
||||
/**
|
||||
@@ -193,6 +232,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* @return the component type, the map's key type or {@literal null} if neither {@link java.util.Collection} nor
|
||||
* {@link java.util.Map}.
|
||||
*/
|
||||
@Nullable
|
||||
Class<?> getComponentType();
|
||||
|
||||
/**
|
||||
@@ -207,6 +247,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return the map's value type or {@literal null} if no {@link java.util.Map}
|
||||
*/
|
||||
@Nullable
|
||||
Class<?> getMapValueType();
|
||||
|
||||
/**
|
||||
@@ -225,15 +266,17 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* @return the annotation of the given type. Can be {@literal null}.
|
||||
* @see AnnotationUtils#findAnnotation(Method, Class)
|
||||
*/
|
||||
@Nullable
|
||||
<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.
|
||||
* Useful to lookup annotations that can be configured on the type but overridden on an individual property.
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return the annotation of the given type. Can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
<A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Domain service to allow accessing and setting {@link PersistentProperty}s of an entity. Usually obtained through
|
||||
@@ -35,10 +36,9 @@ public interface PersistentPropertyAccessor {
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param value can be {@literal null}.
|
||||
* @throws MappingException in case an exception occurred when setting the
|
||||
* property value.
|
||||
* @throws MappingException in case an exception occurred when setting the property value.
|
||||
*/
|
||||
void setProperty(PersistentProperty<?> property, Object value);
|
||||
void setProperty(PersistentProperty<?> property, @Nullable Object value);
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} of the underlying bean instance.
|
||||
@@ -46,6 +46,7 @@ public interface PersistentPropertyAccessor {
|
||||
* @param property must not be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
Object getProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -188,17 +189,17 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
@EqualsAndHashCode(exclude = { "enclosingClassCache", "hasSpelExpression" })
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final String name;
|
||||
private final @Nullable String name;
|
||||
private final TypeInformation<T> type;
|
||||
private final String key;
|
||||
private final PersistentEntity<T, P> entity;
|
||||
private final @Nullable PersistentEntity<T, P> entity;
|
||||
|
||||
private final Lazy<Boolean> enclosingClassCache;
|
||||
private final Lazy<Boolean> hasSpelExpression;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* {@link Annotation}s. Will inspect 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}
|
||||
@@ -206,7 +207,8 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations, PersistentEntity<T, P> entity) {
|
||||
public Parameter(@Nullable String name, TypeInformation<T> type, Annotation[] annotations,
|
||||
@Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(annotations, "Annotations must not be null!");
|
||||
@@ -242,6 +244,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -290,7 +293,11 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
PersistentEntity<T, P> entity = this.entity;
|
||||
String name = this.name;
|
||||
|
||||
P referencedProperty = entity == null ? null : name == null ? null : entity.getPersistentProperty(name);
|
||||
|
||||
return property != null && property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.regex.Pattern;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -57,7 +58,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
private final TypeInformation<?> actualTypeInformation;
|
||||
private final boolean isCollection;
|
||||
|
||||
private PropertyPath next;
|
||||
private @Nullable PropertyPath next;
|
||||
|
||||
/**
|
||||
* Creates a leaf {@link PropertyPath} (no nested ones) with the given name inside the given owning type.
|
||||
@@ -92,8 +93,9 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
this.owningType = owningType;
|
||||
this.typeInformation = propertyType;
|
||||
this.isCollection = propertyType.isCollectionLike();
|
||||
this.actualTypeInformation = propertyType.getActualType();
|
||||
this.name = propertyName;
|
||||
this.actualTypeInformation = propertyType.getActualType() == null ? propertyType
|
||||
: propertyType.getRequiredActualType();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +126,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
PropertyPath result = this;
|
||||
|
||||
while (result.hasNext()) {
|
||||
result = result.next();
|
||||
result = result.requiredNext();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -146,6 +148,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available.
|
||||
* @see #hasNext()
|
||||
*/
|
||||
@Nullable
|
||||
public PropertyPath next() {
|
||||
return next;
|
||||
}
|
||||
@@ -168,7 +171,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
public String toDotPath() {
|
||||
|
||||
if (hasNext()) {
|
||||
return getSegment() + "." + next().toDotPath();
|
||||
return getSegment() + "." + requiredNext().toDotPath();
|
||||
}
|
||||
|
||||
return getSegment();
|
||||
@@ -188,17 +191,25 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<PropertyPath> iterator() {
|
||||
|
||||
return new Iterator<PropertyPath>() {
|
||||
|
||||
private PropertyPath current = PropertyPath.this;
|
||||
private @Nullable PropertyPath current = PropertyPath.this;
|
||||
|
||||
public boolean hasNext() {
|
||||
return current != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PropertyPath next() {
|
||||
|
||||
PropertyPath result = current;
|
||||
this.current = current.next();
|
||||
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.current = result.next();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -208,6 +219,24 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next {@link PropertyPath}.
|
||||
*
|
||||
* @return
|
||||
* @throws IllegalStateException it there's no next one.
|
||||
*/
|
||||
private PropertyPath requiredNext() {
|
||||
|
||||
PropertyPath result = next;
|
||||
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"No next path available! Clients should call hasNext() before invoking this method!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the {@link PropertyPath} chain from the given source {@link String} and type.
|
||||
*
|
||||
@@ -258,6 +287,11 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Expected parsing to yield a PropertyPath from %s but got null!", source));
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
@@ -277,7 +311,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
PropertyPath previous = base.peek();
|
||||
|
||||
PropertyPath propertyPath = create(source, previous.typeInformation.getActualType(), base);
|
||||
PropertyPath propertyPath = create(source, previous.typeInformation.getRequiredActualType(), base);
|
||||
previous.next = propertyPath;
|
||||
return propertyPath;
|
||||
}
|
||||
@@ -297,7 +331,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to look up a chain of {@link PropertyPath}s by trying the givne source first. If that fails it will split the
|
||||
* Tries to look up a chain of {@link PropertyPath}s by trying the given source first. If that fails it will split the
|
||||
* source apart at camel case borders (starting from the right side) and try to look up a {@link PropertyPath} from
|
||||
* the calculated head and recombined new tail and additional tail.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.PropertyMatches;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -118,6 +119,7 @@ public class PropertyReferenceException extends RuntimeException {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public PropertyPath getBaseProperty() {
|
||||
return alreadyResolvedPath.isEmpty() ? null : alreadyResolvedPath.get(alreadyResolvedPath.size() - 1);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -89,7 +90,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
private final Map<TypeAndProperties, PersistentPropertyPath<P>> propertyPaths = new ConcurrentReferenceHashMap<>();
|
||||
private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory = new ClassGeneratingPropertyAccessorFactory();
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
private @Nullable ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private Set<? extends Class<?>> initialEntitySet = new HashSet<>();
|
||||
private boolean strict = false;
|
||||
@@ -131,7 +132,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
/**
|
||||
* Configures the {@link SimpleTypeHolder} to be used by the {@link MappingContext}. Allows customization of what
|
||||
* types will be regarded as simple types and thus not recursively analysed.
|
||||
* types will be regarded as simple types and thus not recursively analyzed.
|
||||
*
|
||||
* @param simpleTypes must not be {@literal null}.
|
||||
*/
|
||||
@@ -166,6 +167,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
@@ -186,6 +188,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
@@ -228,13 +231,14 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
|
||||
Assert.notNull(persistentProperty, "PersistentProperty must not be null!");
|
||||
|
||||
TypeInformation<?> typeInfo = persistentProperty.getTypeInformation();
|
||||
return getPersistentEntity(typeInfo.getActualType());
|
||||
return getPersistentEntity(typeInfo.getRequiredActualType());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -315,6 +319,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
return path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<DefaultPersistentPropertyPath<P>, E> getPair(DefaultPersistentPropertyPath<P> path,
|
||||
Iterator<String> iterator, String segment, E entity) {
|
||||
|
||||
@@ -324,7 +329,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> type = property.getTypeInformation().getActualType();
|
||||
TypeInformation<?> type = property.getTypeInformation().getRequiredActualType();
|
||||
return Pair.of(path.append(property), iterator.hasNext() ? getRequiredPersistentEntity(type) : entity);
|
||||
}
|
||||
|
||||
@@ -520,9 +525,10 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
*/
|
||||
public void addPropertiesForRemainingDescriptors() {
|
||||
|
||||
remainingDescriptors.values().stream()//
|
||||
.map(Property::of)//
|
||||
.filter(PersistentPropertyFilter.INSTANCE::matches)//
|
||||
remainingDescriptors.values().stream() //
|
||||
.filter(Property::supportsStandalone) //
|
||||
.map(Property::of) //
|
||||
.filter(PersistentPropertyFilter.INSTANCE::matches) //
|
||||
.forEach(this::createAndRegisterProperty);
|
||||
}
|
||||
|
||||
@@ -541,7 +547,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
entity.addPersistentProperty(property);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getAssociation());
|
||||
entity.addAssociation(property.getRequiredAssociation());
|
||||
}
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
@@ -621,19 +627,18 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
*/
|
||||
static class PropertyMatch {
|
||||
|
||||
private final String namePattern;
|
||||
private final String typeName;
|
||||
private final @Nullable String namePattern, typeName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyMatch} for the given name pattern and type name. At least one of the paramters
|
||||
* Creates a new {@link PropertyMatch} for the given name pattern and type name. At least one of the parameters
|
||||
* must not be {@literal null}.
|
||||
*
|
||||
* @param namePattern a regex pattern to match field names, can be {@literal null}.
|
||||
* @param typeName the name of the type to exclude, can be {@literal null}.
|
||||
*/
|
||||
public PropertyMatch(String namePattern, String typeName) {
|
||||
public PropertyMatch(@Nullable String namePattern, @Nullable String typeName) {
|
||||
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name patter or type name must be given!");
|
||||
Assert.isTrue(!(namePattern == null && typeName == null), "Either name pattern or type name must be given!");
|
||||
|
||||
this.namePattern = namePattern;
|
||||
this.typeName = typeName;
|
||||
@@ -643,10 +648,14 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* Returns whether the given {@link Field} matches the defined {@link PropertyMatch}.
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public boolean matches(String name, Class<?> type) {
|
||||
|
||||
Assert.notNull(name, "Name must not be null!");
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
if (namePattern != null && !name.matches(namePattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -32,25 +32,19 @@ import org.springframework.util.StringUtils;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements PersistentPropertyPath<T> {
|
||||
class DefaultPersistentPropertyPath<P extends PersistentProperty<P>> implements PersistentPropertyPath<P> {
|
||||
|
||||
private enum PropertyNameConverter implements Converter<PersistentProperty<?>, String> {
|
||||
private static final Converter<PersistentProperty<?>, String> DEFAULT_CONVERTER = (source) -> source.getName();
|
||||
private static final String DEFAULT_DELIMITER = ".";
|
||||
|
||||
INSTANCE;
|
||||
|
||||
public String convert(PersistentProperty<?> source) {
|
||||
return source.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private final List<T> properties;
|
||||
private final List<P> properties;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultPersistentPropertyPath} for the given {@link PersistentProperty}s.
|
||||
*
|
||||
* @param properties must not be {@literal null}.
|
||||
*/
|
||||
public DefaultPersistentPropertyPath(List<T> properties) {
|
||||
public DefaultPersistentPropertyPath(List<P> properties) {
|
||||
|
||||
Assert.notNull(properties, "Properties must not be null!");
|
||||
|
||||
@@ -63,7 +57,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* @return
|
||||
*/
|
||||
public static <T extends PersistentProperty<T>> DefaultPersistentPropertyPath<T> empty() {
|
||||
return new DefaultPersistentPropertyPath<>(Collections.<T> emptyList());
|
||||
return new DefaultPersistentPropertyPath<T>(Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +67,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* @return a new {@link DefaultPersistentPropertyPath} with the given property appended to the current one.
|
||||
* @throws IllegalArgumentException in case the property is not a property of the type of the current leaf property.
|
||||
*/
|
||||
public DefaultPersistentPropertyPath<T> append(T property) {
|
||||
public DefaultPersistentPropertyPath<P> append(P property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
@@ -81,11 +75,13 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
return new DefaultPersistentPropertyPath<>(Collections.singletonList(property));
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
Class<?> leafPropertyType = getLeafProperty().getActualType();
|
||||
|
||||
Assert.isTrue(property.getOwner().getType().equals(leafPropertyType),
|
||||
String.format("Cannot append property %s to type %s!", property.getName(), leafPropertyType.getName()));
|
||||
|
||||
List<T> properties = new ArrayList<>(this.properties);
|
||||
List<P> properties = new ArrayList<>(this.properties);
|
||||
properties.add(property);
|
||||
|
||||
return new DefaultPersistentPropertyPath<>(properties);
|
||||
@@ -95,56 +91,59 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath()
|
||||
*/
|
||||
@Nullable
|
||||
public String toDotPath() {
|
||||
return toPath(null, null);
|
||||
return toPath(DEFAULT_DELIMITER, DEFAULT_CONVERTER);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toDotPath(org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toDotPath(Converter<? super T, String> converter) {
|
||||
return toPath(null, converter);
|
||||
@Nullable
|
||||
public String toDotPath(Converter<? super P, String> converter) {
|
||||
return toPath(DEFAULT_DELIMITER, converter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String)
|
||||
*/
|
||||
@Nullable
|
||||
public String toPath(String delimiter) {
|
||||
return toPath(delimiter, null);
|
||||
return toPath(delimiter, DEFAULT_CONVERTER);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#toPath(java.lang.String, org.springframework.core.convert.converter.Converter)
|
||||
*/
|
||||
public String toPath(String delimiter, Converter<? super T, String> converter) {
|
||||
@Nullable
|
||||
public String toPath(String delimiter, Converter<? super P, String> converter) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Converter<? super T, String> converterToUse = converter == null
|
||||
? PropertyNameConverter.INSTANCE : converter;
|
||||
String delimiterToUse = delimiter == null ? "." : delimiter;
|
||||
Assert.hasText(delimiter, "Delimiter must not be null or empty!");
|
||||
Assert.notNull(converter, "Converter must not be null!");
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for (T property : properties) {
|
||||
for (P property : properties) {
|
||||
|
||||
String convert = converterToUse.convert(property);
|
||||
String convert = converter.convert(property);
|
||||
|
||||
if (StringUtils.hasText(convert)) {
|
||||
result.add(convert);
|
||||
}
|
||||
}
|
||||
|
||||
return result.isEmpty() ? null : StringUtils.collectionToDelimitedString(result, delimiterToUse);
|
||||
return result.isEmpty() ? null : StringUtils.collectionToDelimitedString(result, delimiter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getLeafProperty()
|
||||
*/
|
||||
public T getLeafProperty() {
|
||||
@Nullable
|
||||
public P getLeafProperty() {
|
||||
return properties.get(properties.size() - 1);
|
||||
}
|
||||
|
||||
@@ -152,7 +151,8 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getBaseProperty()
|
||||
*/
|
||||
public T getBaseProperty() {
|
||||
@Nullable
|
||||
public P getBaseProperty() {
|
||||
return properties.get(0);
|
||||
}
|
||||
|
||||
@@ -160,21 +160,19 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#isBasePathOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public boolean isBasePathOf(PersistentPropertyPath<T> path) {
|
||||
public boolean isBasePathOf(PersistentPropertyPath<P> path) {
|
||||
|
||||
if (path == null) {
|
||||
return false;
|
||||
}
|
||||
Assert.notNull(path, "PersistentPropertyPath must not be null!");
|
||||
|
||||
Iterator<T> iterator = path.iterator();
|
||||
Iterator<P> iterator = path.iterator();
|
||||
|
||||
for (T property : this) {
|
||||
for (P property : this) {
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T reference = iterator.next();
|
||||
P reference = iterator.next();
|
||||
|
||||
if (!property.equals(reference)) {
|
||||
return false;
|
||||
@@ -188,14 +186,14 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getExtensionForBaseOf(org.springframework.data.mapping.context.PersistentPropertyPath)
|
||||
*/
|
||||
public PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base) {
|
||||
public PersistentPropertyPath<P> getExtensionForBaseOf(PersistentPropertyPath<P> base) {
|
||||
|
||||
if (!base.isBasePathOf(this)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<>();
|
||||
Iterator<T> iterator = iterator();
|
||||
List<P> result = new ArrayList<>();
|
||||
Iterator<P> iterator = iterator();
|
||||
|
||||
for (int i = 0; i < base.getLength(); i++) {
|
||||
iterator.next();
|
||||
@@ -212,11 +210,14 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.PersistentPropertyPath#getParentPath()
|
||||
*/
|
||||
public PersistentPropertyPath<T> getParentPath() {
|
||||
public PersistentPropertyPath<P> getParentPath() {
|
||||
|
||||
int size = properties.size();
|
||||
|
||||
if (size <= 1) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<>(properties.subList(0, size - 1));
|
||||
}
|
||||
|
||||
@@ -232,7 +233,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
public Iterator<P> iterator() {
|
||||
return properties.iterator();
|
||||
}
|
||||
|
||||
@@ -249,7 +250,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
@@ -278,6 +279,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String toString() {
|
||||
return toDotPath();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mapping.context;
|
||||
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -40,8 +41,8 @@ public class InvalidPersistentPropertyPath extends MappingException {
|
||||
* @param resolvedPath
|
||||
* @param message must not be {@literal null} or empty.
|
||||
*/
|
||||
InvalidPersistentPropertyPath(String source, TypeInformation<?> type, String unresolvableSegment, String resolvedPath,
|
||||
String message) {
|
||||
InvalidPersistentPropertyPath(String source, TypeInformation<?> type, String unresolvableSegment,
|
||||
@Nullable String resolvedPath, String message) {
|
||||
|
||||
super(message);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* This interface defines the overall context including all known PersistentEntity instances and methods to obtain
|
||||
@@ -51,6 +52,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return {@literal null} if no {@link PersistentEntity} found for {@literal type}.
|
||||
*/
|
||||
@Nullable
|
||||
E getPersistentEntity(Class<?> type);
|
||||
|
||||
/**
|
||||
@@ -91,6 +93,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return {@literal null} if no {@link PersistentEntity} found for {@link TypeInformation}.
|
||||
*/
|
||||
@Nullable
|
||||
E getPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
/**
|
||||
@@ -117,11 +120,12 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param persistentProperty must not be {@literal null}.
|
||||
* @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or null if no
|
||||
* @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or {@literal null} if no
|
||||
* {@link PersistentEntity} exists for it or the {@link PersistentProperty} does not refer to an entity (the
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
@Nullable
|
||||
E getPersistentEntity(P persistentProperty);
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategyFactorySupport;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -68,12 +69,11 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.support.IsNewStrategyFactorySupport#getFallBackStrategy(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
protected IsNewStrategy doGetIsNewStrategy(Class<?> type) {
|
||||
return MappingContextIsNewStrategyFactory.getIsNewStrategy(context.getRequiredPersistentEntity(type));
|
||||
}
|
||||
|
||||
private static IsNewStrategy getIsNewStrategy(PersistentEntity<?, ?> entity) {
|
||||
PersistentEntity<?, ? extends PersistentProperty<?>> entity = context.getRequiredPersistentEntity(type);
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mapping.context;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Abstraction of a path of {@link PersistentProperty}s.
|
||||
@@ -30,33 +31,37 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
String toDotPath();
|
||||
|
||||
/**
|
||||
* Returns the dot based path notation using the given {@link Converter} to translate individual
|
||||
* {@link PersistentProperty}s to path segments.
|
||||
*
|
||||
* @param converter
|
||||
* @param converter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
String toDotPath(Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter based on the {@link PersistentProperty#getName()}.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @param delimiter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
String toPath(String delimiter);
|
||||
|
||||
/**
|
||||
* Returns a {@link String} path with the given delimiter using the given {@link Converter} for
|
||||
* {@link PersistentProperty} to String conversion.
|
||||
*
|
||||
* @param delimiter will default to {@code .} if {@literal null} is given.
|
||||
* @param converter will default to use {@link PersistentProperty#getName()}.
|
||||
* @param delimiter must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
String toPath(String delimiter, Converter<? super T, String> converter);
|
||||
|
||||
/**
|
||||
@@ -66,6 +71,7 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
T getLeafProperty();
|
||||
|
||||
/**
|
||||
@@ -75,13 +81,14 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
T getBaseProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentPropertyPath} is a base path of the current one. This means that the
|
||||
* current {@link PersistentPropertyPath} is basically an extension of the given one.
|
||||
*
|
||||
* @param path
|
||||
* @param path must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
boolean isBasePathOf(PersistentPropertyPath<T> path);
|
||||
@@ -91,7 +98,7 @@ public interface PersistentPropertyPath<T extends PersistentProperty<T>> extends
|
||||
* {@code foo.bar} and a given base {@code foo} it would return {@code bar}. If the given path is not a base of the
|
||||
* the current one the current {@link PersistentPropertyPath} will be returned as is.
|
||||
*
|
||||
* @param base
|
||||
* @param base must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
PersistentPropertyPath<T> getExtensionForBaseOf(PersistentPropertyPath<T> base);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Mapping context API and implementation base classes.
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
@@ -31,9 +31,10 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link PersistentProperty}.
|
||||
@@ -48,7 +49,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
private static final Field CAUSE_FIELD;
|
||||
|
||||
static {
|
||||
CAUSE_FIELD = ReflectionUtils.findField(Throwable.class, "cause");
|
||||
CAUSE_FIELD = ReflectionUtils.findRequiredField(Throwable.class, "cause");
|
||||
}
|
||||
|
||||
private final String name;
|
||||
@@ -56,14 +57,15 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
private final Class<?> rawType;
|
||||
private final Lazy<Association<P>> association;
|
||||
private final @Getter PersistentEntity<?, P> owner;
|
||||
private final @Getter(AccessLevel.PROTECTED) Property property;
|
||||
|
||||
private final @Getter(value = AccessLevel.PROTECTED, onMethod = @__(@SuppressWarnings("null"))) 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;
|
||||
private final @Getter(onMethod = @__(@Nullable)) Method getter;
|
||||
private final @Getter(onMethod = @__(@Nullable)) Method setter;
|
||||
private final @Getter(onMethod = @__(@Nullable)) Field field;
|
||||
|
||||
public AbstractPersistentProperty(Property property, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
@@ -81,6 +83,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
|
||||
this.hashCode = Lazy.of(property::hashCode);
|
||||
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())//
|
||||
@@ -145,38 +148,12 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
.orElseGet(Collections::emptySet);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getGetter()
|
||||
*/
|
||||
@Override
|
||||
public Method getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSetter()
|
||||
*/
|
||||
@Override
|
||||
public Method getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getField()
|
||||
*/
|
||||
@Override
|
||||
public Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public String getSpelExpression() {
|
||||
return null;
|
||||
}
|
||||
@@ -212,9 +189,10 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getAssociation()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Association<P> getAssociation() {
|
||||
return association.get();
|
||||
return association.orElse(null);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -257,6 +235,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getComponentType()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<?> getComponentType() {
|
||||
return isMap() || isCollectionLike() ? information.getRequiredComponentType().getType() : null;
|
||||
@@ -266,6 +245,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getMapValueType()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<?> getMapValueType() {
|
||||
|
||||
@@ -286,7 +266,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getActualType() {
|
||||
return information.getActualType().getType();
|
||||
return information.getRequiredActualType().getType();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -302,7 +282,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -53,7 +54,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
|
||||
private static final String SPRING_DATA_PACKAGE = "org.springframework.data";
|
||||
|
||||
private final String value;
|
||||
private final @Nullable String value;
|
||||
private final Map<Class<? extends Annotation>, Optional<? extends Annotation>> annotationCache = new HashMap<>();
|
||||
|
||||
private final Lazy<Boolean> usePropertyAccess = Lazy.of(() -> {
|
||||
@@ -159,6 +160,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
*
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value;
|
||||
@@ -216,6 +218,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return {@literal null} if annotation type not found on property.
|
||||
*/
|
||||
@Nullable
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
@@ -248,6 +251,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#findPropertyOrOwnerAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.mapping.TargetAwareIdentifierAccessor;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -69,19 +70,19 @@ 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 final PreferredConstructor<T, P> constructor;
|
||||
private final @Nullable PreferredConstructor<T, P> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final List<P> properties;
|
||||
private final List<P> persistentPropertiesCache;
|
||||
private final Comparator<P> comparator;
|
||||
private final @Nullable Comparator<P> comparator;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private final Map<String, P> propertyCache;
|
||||
private final Map<Class<? extends Annotation>, Optional<Annotation>> annotationCache;
|
||||
private final MultiValueMap<Class<? extends Annotation>, P> propertyAnnotationCache;
|
||||
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
private @Nullable P idProperty;
|
||||
private @Nullable P versionProperty;
|
||||
private PersistentPropertyAccessorFactory propertyAccessorFactory;
|
||||
|
||||
private final Lazy<Alias> typeAlias;
|
||||
@@ -103,7 +104,7 @@ 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, Comparator<P> comparator) {
|
||||
public BasicPersistentEntity(TypeInformation<T> information, @Nullable Comparator<P> comparator) {
|
||||
|
||||
Assert.notNull(information, "Information must not be null!");
|
||||
|
||||
@@ -125,6 +126,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
@Nullable
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
@@ -165,6 +167,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
@Nullable
|
||||
public P getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
@@ -173,6 +176,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
@Nullable
|
||||
public P getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
@@ -223,12 +227,15 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
if (this.versionProperty != null) {
|
||||
P versionProperty = this.versionProperty;
|
||||
|
||||
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()));
|
||||
if (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(), versionProperty.getField()));
|
||||
}
|
||||
|
||||
this.versionProperty = property;
|
||||
@@ -241,15 +248,18 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @param property the new id property candidate, will never be {@literal null}.
|
||||
* @return the given id property or {@literal null} if the given property is not an id property.
|
||||
*/
|
||||
@Nullable
|
||||
protected P returnPropertyIfBetterIdPropertyCandidateOrNull(P property) {
|
||||
|
||||
if (!property.isIdProperty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.idProperty != null) {
|
||||
P idProperty = this.idProperty;
|
||||
|
||||
if (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(), this.idProperty.getField()));
|
||||
+ "as id. Check your mapping configuration!", property.getField(), idProperty.getField()));
|
||||
}
|
||||
|
||||
return property;
|
||||
@@ -273,6 +283,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public P getPersistentProperty(String name) {
|
||||
return propertyCache.get(name);
|
||||
}
|
||||
@@ -384,8 +395,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#findAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
return doFindAnnotation(annotationType).orElse(null);
|
||||
}
|
||||
@@ -399,6 +410,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
return doFindAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
|
||||
|
||||
return (Optional<A>) annotationCache.computeIfAbsent(annotationType,
|
||||
@@ -492,6 +504,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getIdentifier() {
|
||||
return null;
|
||||
}
|
||||
@@ -513,7 +526,16 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public int compare(Association<P> left, Association<P> right) {
|
||||
public int compare(@Nullable Association<P> left, @Nullable Association<P> right) {
|
||||
|
||||
if (left == null) {
|
||||
throw new IllegalArgumentException("Left argument must not be null!");
|
||||
}
|
||||
|
||||
if (right == null) {
|
||||
throw new IllegalArgumentException("Right argument must not be null!");
|
||||
}
|
||||
|
||||
return delegate.compare(left.getInverse(), right.getInverse());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -49,7 +50,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#setProperty(org.springframework.data.mapping.PersistentProperty, java.util.Optional)
|
||||
*/
|
||||
public void setProperty(PersistentProperty<?> property, Object value) {
|
||||
public void setProperty(PersistentProperty<?> property, @Nullable Object value) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
@@ -57,20 +58,17 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
Field field = property.getField();
|
||||
Field field = property.getRequiredField();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, value);
|
||||
return;
|
||||
}
|
||||
|
||||
Method setter = property.getSetter();
|
||||
Method setter = property.getRequiredSetter();
|
||||
|
||||
if (setter != null) {
|
||||
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, value);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, value);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException("Could not set object property!", e);
|
||||
@@ -81,6 +79,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
return getProperty(property, property.getType());
|
||||
}
|
||||
@@ -94,7 +93,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* @return
|
||||
* @throws MappingException in case an exception occured when accessing the property.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public <S> Object getProperty(PersistentProperty<?> property, Class<? extends S> type) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
@@ -103,20 +102,16 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
Field field = property.getField();
|
||||
Field field = property.getRequiredField();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return ReflectionUtils.getField(field, bean);
|
||||
}
|
||||
|
||||
Method getter = property.getGetter();
|
||||
Method getter = property.getRequiredGetter();
|
||||
|
||||
if (getter != null) {
|
||||
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
return ReflectionUtils.invokeMethod(getter, bean);
|
||||
}
|
||||
|
||||
return null;
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
return ReflectionUtils.invokeMethod(getter, bean);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException(
|
||||
|
||||
@@ -50,8 +50,8 @@ import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A factory that can generate byte code to speed-up dynamic property access. Uses the {@link PersistentEntity}'s
|
||||
@@ -530,6 +530,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
* Retrieve all classes which are involved in property/getter/setter declarations as these elements may be
|
||||
* distributed across the type hierarchy.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
private static List<Class<?>> getPropertyDeclaratingClasses(List<PersistentProperty<?>> persistentProperties) {
|
||||
|
||||
return persistentProperties.stream().flatMap(property -> {
|
||||
@@ -854,7 +855,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
}
|
||||
} else {
|
||||
|
||||
Field field = property.getField();
|
||||
Field field = property.getRequiredField();
|
||||
|
||||
if (generateMethodHandle(entity, field)) {
|
||||
// $fieldGetter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
|
||||
@@ -1111,7 +1113,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
return !(Modifier.isPrivate(modifiers) || Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers));
|
||||
}
|
||||
|
||||
private static boolean generateSetterMethodHandle(PersistentEntity<?, ?> entity, Field field) {
|
||||
private static boolean generateSetterMethodHandle(PersistentEntity<?, ?> entity, @Nullable Field field) {
|
||||
|
||||
if (field == null) {
|
||||
return false;
|
||||
@@ -1125,7 +1127,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
* its declaring class. Use also {@link java.lang.invoke.MethodHandle} if visibility is protected/package-default
|
||||
* and packages of the declaring types are different.
|
||||
*/
|
||||
private static boolean generateMethodHandle(PersistentEntity<?, ?> entity, Member member) {
|
||||
private static boolean generateMethodHandle(PersistentEntity<?, ?> entity, @Nullable Member member) {
|
||||
|
||||
if (member == null) {
|
||||
return false;
|
||||
@@ -1143,6 +1145,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1358,8 +1361,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(PropertyStackAddress o) {
|
||||
return (hash < o.hash) ? -1 : ((hash == o.hash) ? 0 : 1);
|
||||
public int compareTo(@SuppressWarnings("null") PropertyStackAddress o) {
|
||||
return hash < o.hash ? -1 : hash == o.hash ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1398,8 +1401,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
ClassLoader classLoader = entity.getType().getClassLoader();
|
||||
Class<?> classLoaderClass = classLoader.getClass();
|
||||
|
||||
Method defineClass = ReflectionUtils.findMethod(classLoaderClass, "defineClass", String.class, byte[].class,
|
||||
Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
||||
Method defineClass = org.springframework.data.util.ReflectionUtils.findRequiredMethod(classLoaderClass,
|
||||
"defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
||||
|
||||
defineClass.setAccessible(true);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mapping.model;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -55,7 +56,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#setProperty(org.springframework.data.mapping.PersistentProperty, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setProperty(PersistentProperty<?> property, Object value) {
|
||||
public void setProperty(PersistentProperty<?> property, @Nullable Object value) {
|
||||
accessor.setProperty(property, convertIfNecessary(value, property.getType()));
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
return accessor.getProperty(property);
|
||||
@@ -75,6 +77,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T getProperty(PersistentProperty<?> property, Class<T> targetType) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
@@ -100,8 +103,9 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertIfNecessary(Object source, Class<T> type) {
|
||||
private <T> T convertIfNecessary(@Nullable Object source, Class<T> type) {
|
||||
return (T) (source == null ? null
|
||||
: type.isAssignableFrom(source.getClass()) ? source : conversionService.convert(source, type));
|
||||
}
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} implementation that evaluates the {@link Parameter}s key against
|
||||
@@ -27,23 +31,17 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
|
||||
|
||||
private final Object source;
|
||||
private final SpELContext factory;
|
||||
private final @NonNull Object source;
|
||||
private final @NonNull SpELContext factory;
|
||||
|
||||
/**
|
||||
* @param source
|
||||
* @param factory
|
||||
*/
|
||||
public DefaultSpELExpressionEvaluator(Object source, SpELContext factory) {
|
||||
this.source = source;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.SpELExpressionEvaluator#evaluate(java.lang.String)
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T evaluate(String expression) {
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.TargetAwareIdentifierAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -57,6 +58,7 @@ public class IdPropertyIdentifierAccessor extends TargetAwareIdentifierAccessor
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
@Nullable
|
||||
public Object getIdentifier() {
|
||||
return accessor.getProperty(idProperty);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -63,8 +64,8 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
this(Optional.empty(), arguments, null, cause);
|
||||
}
|
||||
|
||||
private MappingInstantiationException(Optional<PersistentEntity<?, ?>> entity, List<Object> arguments, String message,
|
||||
Exception cause) {
|
||||
private MappingInstantiationException(Optional<PersistentEntity<?, ?>> entity, List<Object> arguments,
|
||||
@Nullable String message, Exception cause) {
|
||||
|
||||
super(buildExceptionMessage(entity, arguments, message), cause);
|
||||
|
||||
@@ -75,13 +76,13 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(Optional<PersistentEntity<?, ?>> entity, List<Object> arguments,
|
||||
String defaultMessage) {
|
||||
@Nullable String defaultMessage) {
|
||||
|
||||
return entity.map(it -> {
|
||||
|
||||
Optional<? extends PreferredConstructor<?, ?>> constructor = Optional.ofNullable(it.getPersistenceConstructor());
|
||||
|
||||
List<String> toStringArgs = new ArrayList<>(arguments.size());
|
||||
|
||||
for (Object o : arguments) {
|
||||
toStringArgs.add(ObjectUtils.nullSafeToString(o));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Callback interface to lookup values for a given {@link Parameter}.
|
||||
@@ -31,5 +32,6 @@ public interface ParameterValueProvider<P extends PersistentProperty<P>> {
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
<T> T getParameterValue(Parameter<T, P> parameter);
|
||||
}
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
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.util.Assert;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} based on a {@link PersistentEntity} to use a {@link PropertyValueProvider} to lookup
|
||||
@@ -30,50 +33,39 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class PersistentEntityParameterValueProvider<P extends PersistentProperty<P>>
|
||||
implements ParameterValueProvider<P> {
|
||||
|
||||
private final PersistentEntity<?, P> entity;
|
||||
private final PropertyValueProvider<P> provider;
|
||||
private final Object parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityParameterValueProvider} for the given {@link PersistentEntity} and
|
||||
* {@link PropertyValueProvider}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param provider must not be {@literal null}.
|
||||
* @param parent the parent object being created currently, can be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityParameterValueProvider(PersistentEntity<?, P> entity, PropertyValueProvider<P> provider,
|
||||
Object parent) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
Assert.notNull(provider, "Provider must not be null!");
|
||||
|
||||
this.entity = entity;
|
||||
this.provider = provider;
|
||||
this.parent = parent;
|
||||
}
|
||||
private final @NonNull PersistentEntity<?, P> entity;
|
||||
private final @NonNull PropertyValueProvider<P> provider;
|
||||
private final @Nullable Object parent;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (constructor.isEnclosingClassParameter(parameter)) {
|
||||
if (constructor != null && constructor.isEnclosingClassParameter(parameter)) {
|
||||
return (T) parent;
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(parameter.getName());
|
||||
String name = parameter.getName();
|
||||
|
||||
if (name == null) {
|
||||
throw new MappingException(String.format("Parameter %s does not have a name!", parameter));
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(name);
|
||||
|
||||
if (property == null) {
|
||||
throw new MappingException(String.format("No property %s found on entity %s to bind constructor parameter to!",
|
||||
parameter.getName(), entity.getType()));
|
||||
throw new MappingException(
|
||||
String.format("No property %s found on entity %s to bind constructor parameter to!", name, entity.getType()));
|
||||
}
|
||||
|
||||
return provider.getPropertyValue(property);
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
@@ -40,7 +41,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private PreferredConstructor<T, P> constructor;
|
||||
private @Nullable PreferredConstructor<T, P> constructor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
@@ -66,7 +67,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity
|
||||
*/
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, PersistentEntity<T, P> entity) {
|
||||
protected PreferredConstructorDiscoverer(TypeInformation<T> type, @Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
@@ -106,7 +107,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PreferredConstructor<T, P> buildPreferredConstructor(Constructor<?> constructor,
|
||||
TypeInformation<T> typeInformation, PersistentEntity<T, P> entity) {
|
||||
TypeInformation<T> typeInformation, @Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
@@ -136,6 +137,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public PreferredConstructor<T, P> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -43,20 +46,28 @@ public class Property {
|
||||
private final Optional<Method> getter;
|
||||
private final Optional<Method> setter;
|
||||
|
||||
private final Lazy<String> name;
|
||||
private final Lazy<String> toString;
|
||||
|
||||
private Property(Optional<Field> field, Optional<PropertyDescriptor> descriptor) {
|
||||
|
||||
Assert.isTrue(Optionals.isAnyPresent(field, descriptor), "Either field or descriptor has to be given!");
|
||||
|
||||
this.field = field;
|
||||
this.descriptor = descriptor;
|
||||
this.hashCode = Lazy.of(this::computeHashCode);
|
||||
this.rawType = field.<Class<?>> map(Field::getType)
|
||||
.orElseGet(() -> descriptor.map(PropertyDescriptor::getPropertyType)//
|
||||
.orElse(null));
|
||||
|
||||
this.rawType = withFieldOrDescriptor(Field::getType, PropertyDescriptor::getPropertyType);
|
||||
this.hashCode = Lazy.of(() -> withFieldOrDescriptor(Object::hashCode));
|
||||
this.name = Lazy.of(() -> withFieldOrDescriptor(Field::getName, FeatureDescriptor::getName));
|
||||
this.toString = Lazy.of(() -> withFieldOrDescriptor(Object::toString));
|
||||
|
||||
this.getter = descriptor.map(PropertyDescriptor::getReadMethod)//
|
||||
.filter(it -> getType() != null).filter(it -> getType().isAssignableFrom(it.getReturnType()));
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> getType().isAssignableFrom(it.getReturnType()));
|
||||
|
||||
this.setter = descriptor.map(PropertyDescriptor::getWriteMethod)//
|
||||
.filter(it -> getType() != null).filter(it -> it.getParameterTypes()[0].isAssignableFrom(getType()));
|
||||
.filter(it -> getType() != null)//
|
||||
.filter(it -> it.getParameterTypes()[0].isAssignableFrom(getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,10 +99,12 @@ public class Property {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Property} for the given {@link PropertyDescriptor}.
|
||||
* Creates a new {@link Property} for the given {@link PropertyDescriptor}. The creation might fail if the given
|
||||
* property is not representing a proper property.
|
||||
*
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
* @see #supportsStandalone(PropertyDescriptor)
|
||||
*/
|
||||
public static Property of(PropertyDescriptor descriptor) {
|
||||
|
||||
@@ -100,6 +113,20 @@ public class Property {
|
||||
return new Property(Optional.empty(), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PropertyDescriptor} is supported in for standalone creation of a {@link Property}
|
||||
* instance.
|
||||
*
|
||||
* @param descriptor
|
||||
* @return
|
||||
*/
|
||||
public static boolean supportsStandalone(PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(descriptor, "PropertDescriptor must not be null!");
|
||||
|
||||
return descriptor.getPropertyType() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property is backed by a field.
|
||||
*
|
||||
@@ -142,10 +169,7 @@ public class Property {
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return field.map(Field::getName)//
|
||||
.orElseGet(() -> descriptor.map(FeatureDescriptor::getName)//
|
||||
.orElseThrow(IllegalStateException::new));
|
||||
return this.name.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,27 +181,12 @@ public class Property {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
private int computeHashCode() {
|
||||
|
||||
return this.field.map(Field::hashCode)
|
||||
.orElseGet(() -> this.descriptor.map(PropertyDescriptor::hashCode).orElseThrow(IllegalStateException::new));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
@@ -192,13 +201,47 @@ public class Property {
|
||||
return this.field.isPresent() ? this.field.equals(that.field) : this.descriptor.equals(that.descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return field.map(Object::toString)
|
||||
.orElseGet(() -> descriptor.map(Object::toString).orElseThrow(IllegalStateException::new));
|
||||
return toString.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the backing {@link Field} or {@link PropertyDescriptor} using the given {@link Function}.
|
||||
*
|
||||
* @param function must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <T> T withFieldOrDescriptor(Function<Object, T> function) {
|
||||
return withFieldOrDescriptor(function, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the backing {@link Field} or {@link PropertyDescriptor} using the given functions.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param descriptor must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <T> T withFieldOrDescriptor(Function<? super Field, T> field,
|
||||
Function<? super PropertyDescriptor, T> descriptor) {
|
||||
|
||||
return Optionals.firstNonEmpty(//
|
||||
() -> this.field.map(field), //
|
||||
() -> this.descriptor.map(descriptor))//
|
||||
.orElseThrow(() -> new IllegalStateException("Should not occur! Either field or descriptor has to be given"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 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.
|
||||
@@ -22,6 +22,8 @@ import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple factory to create {@link SpelExpressionParser} and {@link EvaluationContext} instances.
|
||||
@@ -32,7 +34,7 @@ public class SpELContext {
|
||||
|
||||
private final SpelExpressionParser parser;
|
||||
private final PropertyAccessor accessor;
|
||||
private final BeanFactory factory;
|
||||
private final @Nullable BeanFactory factory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELContext} with the given {@link PropertyAccessor}. Defaults the
|
||||
@@ -75,7 +77,9 @@ public class SpELContext {
|
||||
* @param parser
|
||||
* @param factory
|
||||
*/
|
||||
private SpELContext(PropertyAccessor accessor, SpelExpressionParser parser, BeanFactory factory) {
|
||||
private SpELContext(PropertyAccessor accessor, @Nullable SpelExpressionParser parser, @Nullable BeanFactory factory) {
|
||||
|
||||
Assert.notNull(accessor, "PropertyAccessor must not be null!");
|
||||
|
||||
this.parser = parser == null ? new SpelExpressionParser() : parser;
|
||||
this.accessor = accessor;
|
||||
@@ -97,10 +101,7 @@ public class SpELContext {
|
||||
public EvaluationContext getEvaluationContext(Object source) {
|
||||
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(source);
|
||||
|
||||
if (accessor != null) {
|
||||
evaluationContext.addPropertyAccessor(accessor);
|
||||
}
|
||||
evaluationContext.addPropertyAccessor(accessor);
|
||||
|
||||
if (factory != null) {
|
||||
evaluationContext.setBeanResolver(new BeanFactoryResolver(factory));
|
||||
@@ -108,5 +109,4 @@ public class SpELContext {
|
||||
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* SPI for components that can evaluate Spring EL expressions.
|
||||
*
|
||||
@@ -28,5 +30,6 @@ public interface SpELExpressionEvaluator {
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
<T> T evaluate(String expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,50 +15,34 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ParameterValueProvider} that can be used to front a {@link ParameterValueProvider} delegate to prefer a Spel
|
||||
* {@link ParameterValueProvider} that can be used to front a {@link ParameterValueProvider} delegate to prefer a SpEL
|
||||
* expression evaluation over directly resolving the parameter value with the delegate.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P>>
|
||||
implements ParameterValueProvider<P> {
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
private final ParameterValueProvider<P> delegate;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpELExpressionParameterValueProvider} using the given {@link SpELExpressionEvaluator},
|
||||
* {@link ConversionService} and {@link ParameterValueProvider} delegate to forward calls to, that resolve parameters
|
||||
* that do not have a Spel expression configured with them.
|
||||
*
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public SpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator, ConversionService conversionService,
|
||||
ParameterValueProvider<P> delegate) {
|
||||
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null!");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null!");
|
||||
Assert.notNull(delegate, "ParameterValueProvider delegate must not be null!");
|
||||
|
||||
this.evaluator = evaluator;
|
||||
this.conversionService = conversionService;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
private final @NonNull SpELExpressionEvaluator evaluator;
|
||||
private final @NonNull ConversionService conversionService;
|
||||
private final @NonNull ParameterValueProvider<P> delegate;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
if (!parameter.hasSpelExpression()) {
|
||||
@@ -77,6 +61,7 @@ public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P
|
||||
* @param parameter the {@link Parameter} we create the value for
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, P> parameter) {
|
||||
return conversionService.convert(object, parameter.getRawType());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Core implementation of the mapping subsystem's model.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/**
|
||||
* Base package for the mapping subsystem.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
@org.springframework.lang.NonNullApi
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
@@ -44,10 +44,14 @@ public final class Accessor {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
|
||||
this.descriptor = BeanUtils.findPropertyForMethod(method);
|
||||
this.method = method;
|
||||
PropertyDescriptor descriptor = BeanUtils.findPropertyForMethod(method);
|
||||
|
||||
Assert.notNull(descriptor, () -> String.format("Invoked method %s is no accessor method!", method));
|
||||
if (descriptor == null) {
|
||||
throw new IllegalArgumentException(String.format("Invoked method %s is no accessor method!", method));
|
||||
}
|
||||
|
||||
this.descriptor = descriptor;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
@@ -48,8 +50,9 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {
|
||||
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-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.
|
||||
@@ -21,6 +21,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -40,8 +42,9 @@ class MapAccessingMethodInterceptor implements MethodInterceptor {
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {
|
||||
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
|
||||
@@ -26,12 +26,15 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -54,8 +57,9 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@SuppressWarnings("null") @Nonnull MethodInvocation invocation) throws Throwable {
|
||||
|
||||
Object result = delegate.invoke(invocation);
|
||||
|
||||
@@ -121,6 +125,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object getProjection(Object result, Class<?> returnType) {
|
||||
return result == null || ClassUtils.isAssignable(returnType, result.getClass()) ? result
|
||||
: factory.createProjection(returnType, result);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.projection;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A factory to create projecting instances for other objects usually used to allow easy creation of representation
|
||||
* projections to define which properties of a domain objects shall be exported in which way.
|
||||
@@ -29,11 +31,23 @@ public interface ProjectionFactory {
|
||||
* the implementations.
|
||||
*
|
||||
* @param projectionType the type to create, must not be {@literal null}.
|
||||
* @param source the object to create a projection for, can be {@literal null}
|
||||
* @param source the object to create a projection for, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T createProjection(Class<T> projectionType, Object source);
|
||||
|
||||
/**
|
||||
* Creates a projection to the given type for the given nullable source.
|
||||
*
|
||||
* @param projectionType must not be {@literal null}.
|
||||
* @param source can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
default <T> T createNullableProjection(Class<T> projectionType, @Nullable Object source) {
|
||||
return source == null ? null : createProjection(projectionType, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a projection instance for the given type.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -52,8 +53,9 @@ class PropertyAccessingMethodInterceptor implements MethodInterceptor {
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {
|
||||
|
||||
Method method = invocation.getMethod();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user