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:
Oliver Gierke
2017-06-27 08:41:16 +02:00
parent d9b16d8a27
commit 049970874d
234 changed files with 2274 additions and 1179 deletions

View File

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

View File

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

View File

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

View File

@@ -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);
/**

View File

@@ -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);
/**

View File

@@ -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);
/**

View File

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

View File

@@ -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.
*

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
/**

View File

@@ -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()) {

View File

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

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

@@ -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(

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
/**
* Base package for the mapping subsystem.
*/
package org.springframework.data.mapping;
@org.springframework.lang.NonNullApi
package org.springframework.data.mapping;