DATACMNS-867 - First draft.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface for a component allowing the access of identifier values.
|
||||
*
|
||||
@@ -27,5 +29,5 @@ public interface IdentifierAccessor {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getIdentifier();
|
||||
Optional<? extends Object> getIdentifier();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -40,11 +41,11 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
/**
|
||||
* Returns the {@link PreferredConstructor} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
*
|
||||
* @return {@literal null} in case no suitable constructor for automatic construction can be found. This usually
|
||||
* indicates that the instantiation of the object of that persistent entity is done through either a customer
|
||||
* {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
* @return An empty {@link Optional} in case no suitable constructor for automatic construction can be found. This
|
||||
* usually indicates that the instantiation of the object of that persistent entity is done through either a
|
||||
* customer {@link EntityInstantiator} or handled by custom conversion mechanisms entirely.
|
||||
*/
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
Optional<PreferredConstructor<T, P>> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referred to by a constructor argument of the
|
||||
@@ -78,7 +79,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return the id property of the {@link PersistentEntity}.
|
||||
*/
|
||||
P getIdProperty();
|
||||
Optional<P> getIdProperty();
|
||||
|
||||
/**
|
||||
* Returns the version property of the {@link PersistentEntity}. Can be {@literal null} in case no version property is
|
||||
@@ -86,7 +87,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return the version property of the {@link PersistentEntity}.
|
||||
*/
|
||||
P getVersionProperty();
|
||||
Optional<P> getVersionProperty();
|
||||
|
||||
/**
|
||||
* Obtains a {@link PersistentProperty} instance by name.
|
||||
@@ -94,7 +95,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
* @param name The name of the property
|
||||
* @return the {@link PersistentProperty} or {@literal null} if it doesn't exist.
|
||||
*/
|
||||
P getPersistentProperty(String name);
|
||||
Optional<P> getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
* Returns the property equipped with an annotation of the given type.
|
||||
@@ -103,7 +104,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
P getPersistentProperty(Class<? extends Annotation> annotationType);
|
||||
Optional<P> getPersistentProperty(Class<? extends Annotation> annotationType);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has an id property. If this call returns {@literal true},
|
||||
@@ -134,7 +135,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getTypeAlias();
|
||||
Optional<? extends Object> getTypeAlias();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} backing this {@link PersistentEntity}.
|
||||
@@ -169,7 +170,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns a {@link PersistentPropertyAccessor} to access property values of the given bean.
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -74,19 +75,19 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return the getter method to access the property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getGetter();
|
||||
Optional<Method> getGetter();
|
||||
|
||||
/**
|
||||
* Returns the setter method to set a property value. Might return {@literal null} in case there is no setter
|
||||
* available.
|
||||
*
|
||||
* @returnthe setter method to set a property value if available, otherwise {@literal null}.
|
||||
* @return the setter method to set a property value if available, otherwise {@literal null}.
|
||||
*/
|
||||
Method getSetter();
|
||||
Optional<Method> getSetter();
|
||||
|
||||
Field getField();
|
||||
Optional<Field> getField();
|
||||
|
||||
String getSpelExpression();
|
||||
Optional<String> getSpelExpression();
|
||||
|
||||
Association<P> getAssociation();
|
||||
|
||||
@@ -201,7 +202,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* @return the annotation of the given type if present or {@literal null} otherwise.
|
||||
* @see AnnotationUtils#findAnnotation(Method, Class)
|
||||
*/
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> Optional<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.
|
||||
@@ -210,7 +211,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> Optional<A> findPropertyOrOwnerAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentProperty} has an annotation of the given type.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,7 @@ public interface PersistentPropertyAccessor {
|
||||
* @throws org.springframework.data.mapping.model.MappingException in case an exception occurred when setting the
|
||||
* property value.
|
||||
*/
|
||||
void setProperty(PersistentProperty<?> property, Object value);
|
||||
void setProperty(PersistentProperty<?> property, Optional<? extends Object> value);
|
||||
|
||||
/**
|
||||
* Returns the value of the given {@link PersistentProperty} of the underlying bean instance.
|
||||
@@ -47,7 +49,7 @@ public interface PersistentPropertyAccessor {
|
||||
* @param property must not be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
Object getProperty(PersistentProperty<?> property);
|
||||
Optional<? extends Object> getProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns the underlying bean.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -23,11 +23,14 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -56,6 +59,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param constructor must not be {@literal null}.
|
||||
* @param parameters must not be {@literal null}.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public PreferredConstructor(Constructor<T> constructor, Parameter<Object, P>... parameters) {
|
||||
|
||||
Assert.notNull(constructor, "Constructor must not be null!");
|
||||
@@ -80,8 +84,8 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<Parameter<Object, P>> getParameters() {
|
||||
return parameters;
|
||||
public Streamable<Parameter<Object, P>> getParameters() {
|
||||
return Streamable.of(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,15 +185,16 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param <T> the type of the parameter
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@EqualsAndHashCode(exclude = { "enclosingClassCache", "hasSpelExpression" })
|
||||
public static class Parameter<T, P extends PersistentProperty<P>> {
|
||||
|
||||
private final String name;
|
||||
private final Optional<String> name;
|
||||
private final TypeInformation<T> type;
|
||||
private final String key;
|
||||
private final PersistentEntity<T, P> entity;
|
||||
private final Optional<String> key;
|
||||
private final Optional<PersistentEntity<T, P>> entity;
|
||||
|
||||
private Boolean enclosingClassCache;
|
||||
private Boolean hasSpelExpression;
|
||||
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
|
||||
@@ -199,9 +204,10 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @param name the name of the parameter, can be {@literal null}
|
||||
* @param type must not be {@literal null}
|
||||
* @param annotations must not be {@literal null} but can be empty
|
||||
* @param entity can be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations, PersistentEntity<T, P> entity) {
|
||||
public Parameter(Optional<String> name, TypeInformation<T> type, Annotation[] annotations,
|
||||
Optional<PersistentEntity<T, P>> entity) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(annotations, "Annotations must not be null!");
|
||||
@@ -210,23 +216,27 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
this.type = type;
|
||||
this.key = getValue(annotations);
|
||||
this.entity = entity;
|
||||
|
||||
this.enclosingClassCache = Lazy.of(() -> {
|
||||
Class<T> owningType = entity.orElseThrow(() -> new IllegalStateException()).getType();
|
||||
return owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
});
|
||||
|
||||
this.hasSpelExpression = Lazy.of(() -> getSpelExpression().map(StringUtils::hasText).orElse(false));
|
||||
}
|
||||
|
||||
private String getValue(Annotation[] annotations) {
|
||||
for (Annotation anno : annotations) {
|
||||
if (anno.annotationType() == Value.class) {
|
||||
return ((Value) anno).value();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
private static Optional<String> getValue(Annotation[] annotations) {
|
||||
return Arrays.stream(annotations).//
|
||||
filter(it -> it.annotationType() == Value.class).//
|
||||
findFirst().map(it -> ((Value) it).value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the parameter or {@literal null} if none was given.
|
||||
* Returns the name of the parameter.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
public Optional<String> getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -253,7 +263,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSpelExpression() {
|
||||
public Optional<String> getSpelExpression() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -263,12 +273,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
* @return
|
||||
*/
|
||||
public boolean hasSpelExpression() {
|
||||
|
||||
if (this.hasSpelExpression == null) {
|
||||
this.hasSpelExpression = StringUtils.hasText(getSpelExpression());
|
||||
}
|
||||
|
||||
return this.hasSpelExpression;
|
||||
return hasSpelExpression.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,60 +284,17 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
*/
|
||||
boolean maps(PersistentProperty<?> property) {
|
||||
|
||||
P referencedProperty = entity == null ? null : entity.getPersistentProperty(name);
|
||||
return property == null ? false : property.equals(referencedProperty);
|
||||
}
|
||||
|
||||
private boolean isEnclosingClassParameter() {
|
||||
|
||||
if (enclosingClassCache == null) {
|
||||
Class<T> owningType = entity.getType();
|
||||
this.enclosingClassCache = owningType.isMemberClass() && type.getType().equals(owningType.getEnclosingClass());
|
||||
}
|
||||
|
||||
return enclosingClassCache;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Parameter)) {
|
||||
if (!name.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Parameter<?, ?> that = (Parameter<?, ?>) obj;
|
||||
|
||||
boolean nameEquals = this.name == null ? that.name == null : this.name.equals(that.name);
|
||||
boolean keyEquals = this.key == null ? that.key == null : this.key.equals(that.key);
|
||||
boolean entityEquals = this.entity == null ? that.entity == null : this.entity.equals(that.entity);
|
||||
|
||||
// Explicitly delay equals check on type as it might be expensive
|
||||
return nameEquals && keyEquals && entityEquals && this.type.equals(that.type);
|
||||
return entity//
|
||||
.flatMap(it -> it.getPersistentProperty(name.get()))//
|
||||
.map(it -> property.equals(it)).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * nullSafeHashCode(this.name);
|
||||
result += 31 * nullSafeHashCode(this.key);
|
||||
result += 31 * nullSafeHashCode(this.entity);
|
||||
result += 31 * this.type.hashCode();
|
||||
|
||||
return result;
|
||||
private boolean isEnclosingClassParameter() {
|
||||
return enclosingClassCache.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@@ -24,9 +26,9 @@ import java.util.regex.Matcher;
|
||||
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.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -34,7 +36,8 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PropertyPath implements Iterable<PropertyPath> {
|
||||
@EqualsAndHashCode
|
||||
public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
private static final String DELIMITERS = "_\\.";
|
||||
private static final String ALL_UPPERCASE = "[A-Z0-9._$]+";
|
||||
@@ -170,43 +173,6 @@ public class PropertyPath implements Iterable<PropertyPath> {
|
||||
return isCollection;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyPath that = (PropertyPath) obj;
|
||||
|
||||
return this.name.equals(that.name) && this.type.equals(that.type)
|
||||
&& ObjectUtils.nullSafeEquals(this.next, that.next);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * name.hashCode();
|
||||
result += 31 * type.hashCode();
|
||||
result += 31 * (next == null ? 0 : next.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -43,6 +44,7 @@ import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -251,27 +253,34 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
String segment = iterator.next();
|
||||
P persistentProperty = current.getPersistentProperty(segment);
|
||||
final DefaultPersistentPropertyPath<P> foo = path;
|
||||
final E bar = current;
|
||||
|
||||
if (persistentProperty == null) {
|
||||
Pair<DefaultPersistentPropertyPath<P>, E> pair = getPair(path, iterator, segment, current).orElseThrow(() -> {
|
||||
|
||||
String source = StringUtils.collectionToDelimitedString(parts, ".");
|
||||
String resolvedPath = path.toDotPath();
|
||||
String resolvedPath = foo.toDotPath();
|
||||
|
||||
throw new InvalidPersistentPropertyPath(source, type, segment, resolvedPath,
|
||||
String.format("No property %s found on %s!", segment, current.getName()));
|
||||
}
|
||||
return new InvalidPersistentPropertyPath(source, type, segment, resolvedPath,
|
||||
String.format("No property %s found on %s!", segment, bar.getName()));
|
||||
});
|
||||
|
||||
path = path.append(persistentProperty);
|
||||
|
||||
if (iterator.hasNext()) {
|
||||
current = getPersistentEntity(persistentProperty.getTypeInformation().getActualType());
|
||||
}
|
||||
path = pair.getFirst();
|
||||
current = pair.getSecond();
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private Optional<Pair<DefaultPersistentPropertyPath<P>, E>> getPair(DefaultPersistentPropertyPath<P> path,
|
||||
Iterator<String> iterator, String segment, E entity) {
|
||||
|
||||
Optional<P> persistentProperty = entity.getPersistentProperty(segment);
|
||||
|
||||
return persistentProperty.map(it -> Pair.of(path.append(it),
|
||||
iterator.hasNext() ? getPersistentEntity(it.getTypeInformation().getActualType()) : entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given type to the {@link MappingContext}.
|
||||
*
|
||||
@@ -389,7 +398,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* @param simpleTypeHolder
|
||||
* @return
|
||||
*/
|
||||
protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner,
|
||||
protected abstract P createPersistentProperty(Optional<Field> field, PropertyDescriptor descriptor, E owner,
|
||||
SimpleTypeHolder simpleTypeHolder);
|
||||
|
||||
/*
|
||||
@@ -462,7 +471,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
String fieldName = field.getName();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
createAndRegisterProperty(field, descriptors.get(fieldName));
|
||||
createAndRegisterProperty(Optional.of(field), descriptors.get(fieldName));
|
||||
|
||||
this.remainingDescriptors.remove(fieldName);
|
||||
}
|
||||
@@ -477,12 +486,12 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
for (PropertyDescriptor descriptor : remainingDescriptors.values()) {
|
||||
if (PersistentPropertyFilter.INSTANCE.matches(descriptor)) {
|
||||
createAndRegisterProperty(null, descriptor);
|
||||
createAndRegisterProperty(Optional.empty(), descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndRegisterProperty(Field field, PropertyDescriptor descriptor) {
|
||||
private void createAndRegisterProperty(Optional<Field> field, PropertyDescriptor descriptor) {
|
||||
|
||||
P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder);
|
||||
|
||||
@@ -511,7 +520,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter rejecting static fields as well as artifically introduced ones. See
|
||||
* Filter rejecting static fields as well as artificially introduced ones. See
|
||||
* {@link PersistentPropertyFilter#UNMAPPED_PROPERTIES} for details.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
|
||||
@@ -72,7 +72,6 @@ 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.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public DefaultPersistentPropertyPath<T> append(T property) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -45,7 +46,6 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
* @deprecated use {@link MappingContextIsNewStrategyFactory(PersistentEntities)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
public MappingContextIsNewStrategyFactory(MappingContext<? extends PersistentEntity<?, ?>, ?> context) {
|
||||
this(new PersistentEntities(Arrays.asList(context)));
|
||||
}
|
||||
@@ -76,9 +76,9 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
}
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
return new PropertyIsNullOrZeroNumberIsNewStrategy(entity.getVersionProperty());
|
||||
return new PropertyIsNullOrZeroNumberIsNewStrategy(entity.getVersionProperty().get());
|
||||
} else if (entity.hasIdProperty()) {
|
||||
return new PropertyIsNullIsNewStrategy(entity.getIdProperty());
|
||||
return new PropertyIsNullIsNewStrategy(entity.getIdProperty().get());
|
||||
} else {
|
||||
throw new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type));
|
||||
}
|
||||
@@ -104,16 +104,21 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.IsNewStrategy#isNew(java.lang.Object)
|
||||
* @see org.springframework.data.support.IsNewStrategy#isNew(java.util.Optional)
|
||||
*/
|
||||
public boolean isNew(Object entity) {
|
||||
@Override
|
||||
public boolean isNew(Optional<? extends Object> entity) {
|
||||
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(entity);
|
||||
Object propertyValue = accessor.getProperty(property);
|
||||
return entity.map(it -> {
|
||||
|
||||
return decideIsNew(propertyValue);
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(it);
|
||||
Object propertyValue = accessor.getProperty(property);
|
||||
|
||||
return decideIsNew(propertyValue);
|
||||
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
protected abstract boolean decideIsNew(Object property);
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -46,25 +46,25 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
}
|
||||
|
||||
protected final String name;
|
||||
protected final PropertyDescriptor propertyDescriptor;
|
||||
protected final Optional<PropertyDescriptor> propertyDescriptor;
|
||||
protected final TypeInformation<?> information;
|
||||
protected final Class<?> rawType;
|
||||
protected final Field field;
|
||||
protected final Optional<Field> field;
|
||||
protected final Association<P> association;
|
||||
protected final PersistentEntity<?, P> owner;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
private final int hashCode;
|
||||
|
||||
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
public AbstractPersistentProperty(Optional<Field> field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
Assert.notNull(simpleTypeHolder, "SimpleTypeHolder must not be null!");
|
||||
Assert.notNull(owner, "Owner entity must not be null!");
|
||||
|
||||
this.name = field == null ? propertyDescriptor.getName() : field.getName();
|
||||
this.rawType = field == null ? propertyDescriptor.getPropertyType() : field.getType();
|
||||
this.name = field.map(Field::getName).orElseGet(() -> propertyDescriptor.getName());
|
||||
this.rawType = field.<Class<?>> map(Field::getType).orElseGet(() -> propertyDescriptor.getPropertyType());
|
||||
this.information = owner.getTypeInformation().getProperty(this.name);
|
||||
this.propertyDescriptor = propertyDescriptor;
|
||||
this.propertyDescriptor = Optional.ofNullable(propertyDescriptor);
|
||||
this.field = field;
|
||||
this.association = isAssociation() ? createAssociation() : null;
|
||||
this.owner = owner;
|
||||
@@ -150,19 +150,9 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getGetter()
|
||||
*/
|
||||
@Override
|
||||
public Method getGetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method getter = propertyDescriptor.getReadMethod();
|
||||
|
||||
if (getter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return rawType.isAssignableFrom(getter.getReturnType()) ? getter : null;
|
||||
public Optional<Method> getGetter() {
|
||||
return propertyDescriptor.map(it -> it.getReadMethod())//
|
||||
.filter(it -> rawType.isAssignableFrom(it.getReturnType()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,19 +160,9 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSetter()
|
||||
*/
|
||||
@Override
|
||||
public Method getSetter() {
|
||||
|
||||
if (propertyDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method setter = propertyDescriptor.getWriteMethod();
|
||||
|
||||
if (setter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return setter.getParameterTypes()[0].isAssignableFrom(rawType) ? setter : null;
|
||||
public Optional<Method> getSetter() {
|
||||
return propertyDescriptor.map(it -> it.getWriteMethod())//
|
||||
.filter(it -> it.getParameterTypes()[0].isAssignableFrom(rawType));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -190,7 +170,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getField()
|
||||
*/
|
||||
@Override
|
||||
public Field getField() {
|
||||
public Optional<Field> getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@@ -199,8 +179,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return null;
|
||||
public Optional<String> getSpelExpression() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -227,7 +207,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
return field == null ? false : AnnotationUtils.getAnnotation(field, Reference.class) != null;
|
||||
return isAnnotationPresent(Reference.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -351,6 +331,8 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.field == null ? this.propertyDescriptor.toString() : this.field.toString();
|
||||
return field.map(Object::toString)//
|
||||
.orElseGet(() -> propertyDescriptor.map(Object::toString)//
|
||||
.orElseThrow(() -> new IllegalStateException("Either Field or PropertyDescriptor has to be present!")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,14 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -36,6 +39,7 @@ import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -44,13 +48,13 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends
|
||||
AbstractPersistentProperty<P> {
|
||||
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>>
|
||||
extends AbstractPersistentProperty<P> {
|
||||
|
||||
private static final String SPRING_DATA_PACKAGE = "org.springframework.data";
|
||||
|
||||
private final Value value;
|
||||
private final Map<Class<? extends Annotation>, Annotation> annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
|
||||
private final Optional<Value> value;
|
||||
private final Map<Class<? extends Annotation>, Optional<? extends Annotation>> annotationCache = new HashMap<>();
|
||||
|
||||
private Boolean isTransient;
|
||||
private boolean usePropertyAccess;
|
||||
@@ -62,15 +66,15 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @param propertyDescriptor can be {@literal null}.
|
||||
* @param owner must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
public AnnotationBasedPersistentProperty(Optional<Field> field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
|
||||
populateAnnotationCache(field);
|
||||
|
||||
AccessType accessType = findPropertyOrOwnerAnnotation(AccessType.class);
|
||||
this.usePropertyAccess = accessType == null ? false : Type.PROPERTY.equals(accessType.value());
|
||||
this.usePropertyAccess = findPropertyOrOwnerAnnotation(AccessType.class).map(it -> Type.PROPERTY.equals(it.value()))
|
||||
.orElse(false);
|
||||
this.value = findAnnotation(Value.class);
|
||||
}
|
||||
|
||||
@@ -81,40 +85,36 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @param field
|
||||
* @throws MappingException in case we find an ambiguous mapping on the accessor methods
|
||||
*/
|
||||
private final void populateAnnotationCache(Field field) {
|
||||
private final void populateAnnotationCache(Optional<Field> field) {
|
||||
|
||||
for (Method method : Arrays.asList(getGetter(), getSetter())) {
|
||||
Optionals.toStream(getGetter(), getSetter()).forEach(it -> {
|
||||
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Annotation annotation : method.getAnnotations()) {
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
|
||||
validateAnnotation(annotation, "Ambiguous mapping! Annotation %s configured "
|
||||
+ "multiple times on accessor methods of property %s in class %s!", annotationType.getSimpleName(),
|
||||
getName(), getOwner().getType().getSimpleName());
|
||||
validateAnnotation(annotation,
|
||||
"Ambiguous mapping! Annotation %s configured "
|
||||
+ "multiple times on accessor methods of property %s in class %s!",
|
||||
annotationType.getSimpleName(), getName(), getOwner().getType().getSimpleName());
|
||||
|
||||
annotationCache.put(annotationType, annotation);
|
||||
annotationCache.put(annotationType, Optional.of(annotation));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (field == null) {
|
||||
return;
|
||||
}
|
||||
field.ifPresent(it -> {
|
||||
|
||||
for (Annotation annotation : field.getAnnotations()) {
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
|
||||
validateAnnotation(annotation, "Ambiguous mapping! Annotation %s configured "
|
||||
+ "on field %s and one of its accessor methods in class %s!", annotationType.getSimpleName(),
|
||||
field.getName(), getOwner().getType().getSimpleName());
|
||||
validateAnnotation(annotation,
|
||||
"Ambiguous mapping! Annotation %s configured " + "on field %s and one of its accessor methods in class %s!",
|
||||
annotationType.getSimpleName(), it.getName(), getOwner().getType().getSimpleName());
|
||||
|
||||
annotationCache.put(annotationType, annotation);
|
||||
}
|
||||
annotationCache.put(annotationType, Optional.of(annotation));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +133,8 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
return;
|
||||
}
|
||||
|
||||
if (annotationCache.containsKey(annotationType) && !annotationCache.get(annotationType).equals(candidate)) {
|
||||
if (annotationCache.containsKey(annotationType)
|
||||
&& !annotationCache.get(annotationType).equals(Optional.of(candidate))) {
|
||||
throw new MappingException(String.format(message, arguments));
|
||||
}
|
||||
}
|
||||
@@ -145,8 +146,8 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
|
||||
*/
|
||||
@Override
|
||||
public String getSpelExpression() {
|
||||
return value == null ? null : value.value();
|
||||
public Optional<String> getSpelExpression() {
|
||||
return value.map(Value::value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,29 +210,18 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
public <A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
if (annotationCache != null && annotationCache.containsKey(annotationType)) {
|
||||
return (A) annotationCache.get(annotationType);
|
||||
return (Optional<A>) annotationCache.get(annotationType);
|
||||
}
|
||||
|
||||
for (Method method : Arrays.asList(getGetter(), getSetter())) {
|
||||
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
A annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType);
|
||||
|
||||
if (annotation != null) {
|
||||
return cacheAndReturn(annotationType, annotation);
|
||||
}
|
||||
}
|
||||
|
||||
return cacheAndReturn(annotationType,
|
||||
field == null ? null : AnnotatedElementUtils.findMergedAnnotation(field, annotationType));
|
||||
return cacheAndReturn(annotationType, getAccessors()//
|
||||
.map(it -> it.map(inner -> AnnotatedElementUtils.findMergedAnnotation(inner, annotationType)))//
|
||||
.flatMap(it -> Optionals.toStream(it))//
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -239,10 +229,10 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @see org.springframework.data.mapping.PersistentProperty#findPropertyOrOwnerAnnotation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
public <A extends Annotation> Optional<A> findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
|
||||
A annotation = findAnnotation(annotationType);
|
||||
return annotation == null ? owner.findAnnotation(annotationType) : annotation;
|
||||
Optional<A> annotation = findAnnotation(annotationType);
|
||||
return annotation.isPresent() ? annotation : owner.findAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,7 +241,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @param annotation
|
||||
* @return
|
||||
*/
|
||||
private <A extends Annotation> A cacheAndReturn(Class<? extends A> type, A annotation) {
|
||||
private <A extends Annotation> Optional<A> cacheAndReturn(Class<? extends A> type, Optional<A> annotation) {
|
||||
|
||||
if (annotationCache != null) {
|
||||
annotationCache.put(type, annotation);
|
||||
@@ -267,7 +257,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* @return
|
||||
*/
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return findAnnotation(annotationType) != null;
|
||||
return findAnnotation(annotationType).isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -290,14 +280,15 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
populateAnnotationCache(field);
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (Annotation annotation : annotationCache.values()) {
|
||||
if (annotation != null) {
|
||||
builder.append(annotation.toString()).append(" ");
|
||||
}
|
||||
}
|
||||
StringBuilder builder = new StringBuilder().append(annotationCache.values().stream()//
|
||||
.flatMap(it -> Optionals.toStream(it))//
|
||||
.map(Object::toString)//
|
||||
.collect(Collectors.joining(" ")));
|
||||
|
||||
return builder.toString() + super.toString();
|
||||
}
|
||||
|
||||
private Stream<Optional<? extends AnnotatedElement>> getAccessors() {
|
||||
return Arrays.<Optional<? extends AnnotatedElement>> asList(getGetter(), getSetter(), getField()).stream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@@ -44,6 +45,7 @@ import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.SimpleAssociationHandler;
|
||||
import org.springframework.data.mapping.SimplePropertyHandler;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -64,26 +66,28 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)!";
|
||||
private static final String NULL_ASSOCIATION = "%s.addAssociation(…) was called with a null association! Usually indicates a problem in a Spring Data MappingContext implementation. Be sure to file a bug at https://jira.spring.io!";
|
||||
|
||||
private final PreferredConstructor<T, P> constructor;
|
||||
private final Optional<PreferredConstructor<T, P>> constructor;
|
||||
private final TypeInformation<T> information;
|
||||
private final List<P> properties;
|
||||
private final Comparator<P> comparator;
|
||||
private final Optional<Comparator<P>> comparator;
|
||||
private final Set<Association<P>> associations;
|
||||
|
||||
private final Map<String, P> propertyCache;
|
||||
private final Map<Class<? extends Annotation>, Annotation> annotationCache;
|
||||
private final Map<Class<? extends Annotation>, Optional<Annotation>> annotationCache;
|
||||
|
||||
private P idProperty;
|
||||
private P versionProperty;
|
||||
private Optional<P> idProperty = Optional.empty();
|
||||
private Optional<P> versionProperty = Optional.empty();
|
||||
private PersistentPropertyAccessorFactory propertyAccessorFactory;
|
||||
|
||||
private final Lazy<Optional<? extends Object>> typeAlias;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public BasicPersistentEntity(TypeInformation<T> information) {
|
||||
this(information, null);
|
||||
this(information, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,27 +98,31 @@ 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, Optional<Comparator<P>> comparator) {
|
||||
|
||||
Assert.notNull(information, "Information must not be null!");
|
||||
|
||||
this.information = information;
|
||||
this.properties = new ArrayList<P>();
|
||||
this.properties = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
this.constructor = new PreferredConstructorDiscoverer<T, P>(information, this).getConstructor();
|
||||
this.associations = comparator == null ? new HashSet<Association<P>>()
|
||||
: new TreeSet<Association<P>>(new AssociationComparator<P>(comparator));
|
||||
this.constructor = new PreferredConstructorDiscoverer<>(this).getConstructor();
|
||||
this.associations = comparator.<Set<Association<P>>> map(it -> new TreeSet<>(new AssociationComparator<>(it)))
|
||||
.orElse(new HashSet<>());
|
||||
|
||||
this.propertyCache = new HashMap<String, P>();
|
||||
this.annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
|
||||
this.propertyCache = new HashMap<>();
|
||||
this.annotationCache = new HashMap<>();
|
||||
this.propertyAccessorFactory = BeanWrapperPropertyAccessorFactory.INSTANCE;
|
||||
|
||||
this.typeAlias = Lazy
|
||||
.of(() -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), TypeAlias.class))//
|
||||
.map(TypeAlias::value).filter(it -> StringUtils.hasText(it)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistenceConstructor()
|
||||
*/
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
public Optional<PreferredConstructor<T, P>> getPersistenceConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
@@ -123,7 +131,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isConstructorArgument(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isConstructorArgument(PersistentProperty<?> property) {
|
||||
return constructor == null ? false : constructor.isConstructorParameter(property);
|
||||
return constructor.map(it -> it.isConstructorParameter(property)).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -131,7 +139,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isIdProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isIdProperty(PersistentProperty<?> property) {
|
||||
return this.idProperty == null ? false : this.idProperty.equals(property);
|
||||
return this.idProperty.map(it -> it.equals(property)).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -139,7 +147,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#isVersionProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public boolean isVersionProperty(PersistentProperty<?> property) {
|
||||
return this.versionProperty == null ? false : this.versionProperty.equals(property);
|
||||
return this.versionProperty.map(it -> it.equals(property)).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,7 +162,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getIdProperty()
|
||||
*/
|
||||
public P getIdProperty() {
|
||||
public Optional<P> getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
@@ -162,7 +170,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getVersionProperty()
|
||||
*/
|
||||
public P getVersionProperty() {
|
||||
public Optional<P> getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
@@ -171,7 +179,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasIdProperty()
|
||||
*/
|
||||
public boolean hasIdProperty() {
|
||||
return idProperty != null;
|
||||
return idProperty.isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -179,7 +187,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#hasVersionProperty()
|
||||
*/
|
||||
public boolean hasVersionProperty() {
|
||||
return versionProperty != null;
|
||||
return versionProperty.isPresent();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -203,20 +211,19 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
P candidate = returnPropertyIfBetterIdPropertyCandidateOrNull(property);
|
||||
|
||||
if (candidate != null) {
|
||||
this.idProperty = candidate;
|
||||
this.idProperty = Optional.of(candidate);
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
|
||||
if (this.versionProperty != null) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!",
|
||||
property.getField(), versionProperty.getField()));
|
||||
}
|
||||
this.versionProperty.ifPresent(it -> {
|
||||
|
||||
this.versionProperty = property;
|
||||
throw new MappingException(
|
||||
String.format("Attempt to add version property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), it.getField()));
|
||||
});
|
||||
|
||||
this.versionProperty = Optional.of(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,10 +239,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.idProperty != null) {
|
||||
this.idProperty.ifPresent(it -> {
|
||||
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(), idProperty.getField()));
|
||||
}
|
||||
+ "as id. Check your mapping configuration!", property.getField(), it.getField()));
|
||||
});
|
||||
|
||||
return property;
|
||||
}
|
||||
@@ -260,8 +267,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
|
||||
*/
|
||||
public P getPersistentProperty(String name) {
|
||||
return propertyCache.get(name);
|
||||
public Optional<P> getPersistentProperty(String name) {
|
||||
return Optional.ofNullable(propertyCache.get(name));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -269,26 +276,20 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public P getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
public Optional<P> getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
for (P property : properties) {
|
||||
if (property.isAnnotationPresent(annotationType)) {
|
||||
return property;
|
||||
}
|
||||
Optional<P> property = properties.stream()//
|
||||
.filter(it -> it.isAnnotationPresent(annotationType))//
|
||||
.findAny();
|
||||
|
||||
if (property.isPresent()) {
|
||||
return property;
|
||||
}
|
||||
|
||||
for (Association<P> association : associations) {
|
||||
|
||||
P property = association.getInverse();
|
||||
|
||||
if (property.isAnnotationPresent(annotationType)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return associations.stream().map(Association::getInverse)//
|
||||
.filter(it -> it.isAnnotationPresent(annotationType)).findAny();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -303,10 +304,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
|
||||
*/
|
||||
public Object getTypeAlias() {
|
||||
|
||||
TypeAlias alias = AnnotatedElementUtils.findMergedAnnotation(getType(), TypeAlias.class);
|
||||
return alias == null ? null : StringUtils.hasText(alias.value()) ? alias.value() : null;
|
||||
public Optional<? extends Object> getTypeAlias() {
|
||||
return typeAlias.get();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -325,11 +324,9 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (P property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
properties.stream()//
|
||||
.filter(it -> !it.isTransient() && !it.isAssociation())//
|
||||
.forEach(it -> handler.doWithPersistentProperty(it));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -341,11 +338,9 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
Assert.notNull(handler, "Handler must not be null!");
|
||||
|
||||
for (PersistentProperty<?> property : properties) {
|
||||
if (!property.isTransient() && !property.isAssociation()) {
|
||||
handler.doWithPersistentProperty(property);
|
||||
}
|
||||
}
|
||||
properties.stream()//
|
||||
.filter(it -> !it.isTransient() && !it.isAssociation())//
|
||||
.forEach(it -> handler.doWithPersistentProperty(it));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -380,16 +375,10 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> A findAnnotation(Class<A> annotationType) {
|
||||
public <A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType) {
|
||||
|
||||
if (annotationCache.containsKey(annotationType)) {
|
||||
return (A) annotationCache.get(annotationType);
|
||||
}
|
||||
|
||||
A annotation = AnnotatedElementUtils.findMergedAnnotation(getType(), annotationType);
|
||||
annotationCache.put(annotationType, annotation);
|
||||
|
||||
return annotation;
|
||||
return (Optional<A>) annotationCache.computeIfAbsent(annotationType,
|
||||
it -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), it)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -397,10 +386,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
|
||||
*/
|
||||
public void verify() {
|
||||
|
||||
if (comparator != null) {
|
||||
Collections.sort(properties, comparator);
|
||||
}
|
||||
comparator.ifPresent(it -> Collections.sort(properties, it));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -455,8 +441,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
@Override
|
||||
public Object getIdentifier() {
|
||||
return null;
|
||||
public Optional<? extends Object> getIdentifier() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -45,9 +46,9 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#setProperty(org.springframework.data.mapping.PersistentProperty, java.lang.Object)
|
||||
* @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, Optional<? extends Object> value) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
@@ -55,18 +56,20 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
ReflectionUtils.makeAccessible(property.getField());
|
||||
ReflectionUtils.setField(property.getField(), bean, value);
|
||||
Field field = property.getField().get();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, bean, value.orElse(null));
|
||||
return;
|
||||
}
|
||||
|
||||
Method setter = property.getSetter();
|
||||
Optional<Method> setter = property.getSetter();
|
||||
|
||||
if (property.usePropertyAccess() && setter != null) {
|
||||
setter.ifPresent(it -> {
|
||||
|
||||
ReflectionUtils.makeAccessible(setter);
|
||||
ReflectionUtils.invokeMethod(setter, bean, value);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(it);
|
||||
ReflectionUtils.invokeMethod(it, bean, value.orElse(null));
|
||||
});
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException("Could not set object property!", e);
|
||||
@@ -77,7 +80,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
public Optional<? extends Object> getProperty(PersistentProperty<?> property) {
|
||||
return getProperty(property, property.getType());
|
||||
}
|
||||
|
||||
@@ -91,7 +94,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* @throws MappingException in case an exception occured when accessing the property.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S> S getProperty(PersistentProperty<?> property, Class<? extends S> type) {
|
||||
public <S> Optional<S> getProperty(PersistentProperty<?> property, Class<? extends S> type) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
@@ -99,20 +102,18 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
|
||||
if (!property.usePropertyAccess()) {
|
||||
|
||||
Field field = property.getField();
|
||||
Field field = property.getField().get();
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return (S) ReflectionUtils.getField(field, bean);
|
||||
return Optional.ofNullable((S) ReflectionUtils.getField(field, bean));
|
||||
}
|
||||
|
||||
Method getter = property.getGetter();
|
||||
Optional<Method> getter = property.getGetter();
|
||||
|
||||
if (property.usePropertyAccess() && getter != null) {
|
||||
return getter.map(it -> {
|
||||
|
||||
ReflectionUtils.makeAccessible(getter);
|
||||
return (S) ReflectionUtils.invokeMethod(getter, bean);
|
||||
}
|
||||
|
||||
return null;
|
||||
ReflectionUtils.makeAccessible(it);
|
||||
return (S) ReflectionUtils.invokeMethod(it, bean);
|
||||
});
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new MappingException(
|
||||
|
||||
@@ -32,8 +32,10 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.Label;
|
||||
@@ -46,6 +48,7 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
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.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -153,7 +156,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
propertyAccessorClass = createAccessorClass(entity);
|
||||
|
||||
map = new HashMap<TypeInformation<?>, Class<PersistentPropertyAccessor>>(map);
|
||||
map = new HashMap<>(map);
|
||||
map.put(entity.getTypeInformation(), propertyAccessorClass);
|
||||
|
||||
this.propertyAccessorClasses = map;
|
||||
@@ -256,6 +259,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static final String JAVA_LANG_REFLECT_METHOD = "java/lang/reflect/Method";
|
||||
private static final String JAVA_LANG_INVOKE_METHOD_HANDLE = "java/lang/invoke/MethodHandle";
|
||||
private static final String JAVA_LANG_CLASS = "java/lang/Class";
|
||||
private static final String JAVA_UTIL_OPTIONAL = "java/util/Optional";
|
||||
private static final String BEAN_FIELD = "bean";
|
||||
private static final String THIS_REF = "this";
|
||||
private static final String PERSISTENT_PROPERTY = "org/springframework/data/mapping/PersistentProperty";
|
||||
@@ -369,30 +373,23 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
for (PersistentProperty<?> property : persistentProperties) {
|
||||
|
||||
Method setter = property.getSetter();
|
||||
|
||||
if (setter != null && generateMethodHandle(entity, setter)) {
|
||||
property.getSetter().filter(it -> generateMethodHandle(entity, it)).ifPresent(it -> {
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, setterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
}
|
||||
|
||||
Method getter = property.getGetter();
|
||||
|
||||
if (getter != null && generateMethodHandle(entity, getter)) {
|
||||
});
|
||||
property.getGetter().filter(it -> generateMethodHandle(entity, it)).ifPresent(it -> {
|
||||
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, getterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
}
|
||||
});
|
||||
|
||||
Field field = property.getField();
|
||||
|
||||
if (field != null && generateSetterMethodHandle(entity, field)) {
|
||||
property.getField().filter(it -> generateSetterMethodHandle(entity, it)).ifPresent(it -> {
|
||||
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,18 +510,18 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
if (property.usePropertyAccess()) {
|
||||
|
||||
if (property.getGetter() != null && generateMethodHandle(entity, property.getGetter())) {
|
||||
property.getGetter().filter(it -> generateMethodHandle(entity, it)).ifPresent(it -> {
|
||||
visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
});
|
||||
|
||||
if (property.getSetter() != null && generateMethodHandle(entity, property.getSetter())) {
|
||||
property.getSetter().filter(it -> generateMethodHandle(entity, it)).ifPresent(it -> {
|
||||
visitPropertySetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (property.getField() != null && generateSetterMethodHandle(entity, property.getField())) {
|
||||
property.getField().filter(it -> generateSetterMethodHandle(entity, it)).ifPresent(it -> {
|
||||
visitFieldGetterSetterInitializer(property, mv, entityClasses, internalClassName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mv.visitLabel(l1);
|
||||
@@ -554,24 +551,13 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
*/
|
||||
private static List<Class<?>> getPropertyDeclaratingClasses(List<PersistentProperty<?>> persistentProperties) {
|
||||
|
||||
Set<Class<?>> entityClassesSet = new HashSet<Class<?>>();
|
||||
return persistentProperties.stream().flatMap(property -> {
|
||||
return Optionals.toStream(property.getField(), property.getGetter(), property.getSetter())
|
||||
|
||||
for (PersistentProperty<?> property : persistentProperties) {
|
||||
.map(it -> it.getDeclaringClass());
|
||||
|
||||
if (property.getField() != null) {
|
||||
entityClassesSet.add(property.getField().getDeclaringClass());
|
||||
}
|
||||
}).collect(Collectors.collectingAndThen(Collectors.toSet(), it -> new ArrayList<>(it)));
|
||||
|
||||
if (property.getGetter() != null) {
|
||||
entityClassesSet.add(property.getGetter().getDeclaringClass());
|
||||
}
|
||||
|
||||
if (property.getSetter() != null) {
|
||||
entityClassesSet.add(property.getSetter().getDeclaringClass());
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<Class<?>>(entityClassesSet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -586,11 +572,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// getter = <entity>.class.getDeclaredMethod()
|
||||
Method getter = property.getGetter();
|
||||
Optional<Method> getter = property.getGetter();
|
||||
|
||||
if (getter != null) {
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, getter.getDeclaringClass()));
|
||||
mv.visitLdcInsn(getter.getName());
|
||||
getter.ifPresent(it -> {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
mv.visitInsn(ICONST_0);
|
||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS);
|
||||
|
||||
@@ -608,7 +595,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflect", String.format("(%s)%s",
|
||||
referenceName(JAVA_LANG_REFLECT_METHOD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
} else {
|
||||
});
|
||||
|
||||
if (!getter.isPresent()) {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
}
|
||||
|
||||
@@ -628,22 +617,22 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// setter = <entity>.class.getDeclaredMethod()
|
||||
Method setter = property.getSetter();
|
||||
Optional<Method> setter = property.getSetter();
|
||||
|
||||
if (setter != null) {
|
||||
setter.ifPresent(it -> {
|
||||
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, setter.getDeclaringClass()));
|
||||
mv.visitLdcInsn(setter.getName());
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
|
||||
mv.visitInsn(ICONST_1);
|
||||
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitInsn(ICONST_0);
|
||||
|
||||
Class<?> parameterType = setter.getParameterTypes()[0];
|
||||
Class<?> parameterType = it.getParameterTypes()[0];
|
||||
|
||||
if (parameterType.isPrimitive()) {
|
||||
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(autoboxType(setter.getParameterTypes()[0])), "TYPE",
|
||||
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(autoboxType(it.getParameterTypes()[0])), "TYPE",
|
||||
referenceName(JAVA_LANG_CLASS));
|
||||
} else {
|
||||
mv.visitLdcInsn(Type.getType(referenceName(parameterType)));
|
||||
@@ -665,7 +654,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflect", String.format("(%s)%s",
|
||||
referenceName(JAVA_LANG_REFLECT_METHOD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
} else {
|
||||
});
|
||||
|
||||
if (!setter.isPresent()) {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
}
|
||||
|
||||
@@ -685,33 +676,35 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
List<Class<?>> entityClasses, String internalClassName) {
|
||||
|
||||
// field = <entity>.class.getDeclaredField()
|
||||
Field field = property.getField();
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, field.getDeclaringClass()));
|
||||
mv.visitLdcInsn(field.getName());
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASS, "getDeclaredField",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_STRING), referenceName(JAVA_LANG_REFLECT_FIELD)), false);
|
||||
mv.visitVarInsn(ASTORE, 1);
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
// field.setAccessible(true)
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitInsn(ICONST_1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_REFLECT_FIELD, SET_ACCESSIBLE, "(Z)V", false);
|
||||
mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, it.getDeclaringClass()));
|
||||
mv.visitLdcInsn(it.getName());
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASS, "getDeclaredField",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_STRING), referenceName(JAVA_LANG_REFLECT_FIELD)), false);
|
||||
mv.visitVarInsn(ASTORE, 1);
|
||||
|
||||
// $fieldGetter = lookup.unreflectGetter(field)
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflectGetter", String.format(
|
||||
"(%s)%s", referenceName(JAVA_LANG_REFLECT_FIELD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
mv.visitFieldInsn(PUTSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
// field.setAccessible(true)
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitInsn(ICONST_1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_REFLECT_FIELD, SET_ACCESSIBLE, "(Z)V", false);
|
||||
|
||||
// $fieldSetter = lookup.unreflectSetter(field)
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflectSetter", String.format(
|
||||
"(%s)%s", referenceName(JAVA_LANG_REFLECT_FIELD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
mv.visitFieldInsn(PUTSTATIC, internalClassName, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
// $fieldGetter = lookup.unreflectGetter(field)
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflectGetter", String.format(
|
||||
"(%s)%s", referenceName(JAVA_LANG_REFLECT_FIELD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
mv.visitFieldInsn(PUTSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
|
||||
// $fieldSetter = lookup.unreflectSetter(field)
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, "unreflectSetter", String.format(
|
||||
"(%s)%s", referenceName(JAVA_LANG_REFLECT_FIELD), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)), false);
|
||||
mv.visitFieldInsn(PUTSTATIC, internalClassName, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
});
|
||||
}
|
||||
|
||||
private static void visitBeanGetter(PersistentEntity<?, ?> entity, String internalClassName, ClassWriter cw) {
|
||||
@@ -851,7 +844,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitLabel(propertyStackMap.get(property.getName()).label);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
|
||||
if (property.getGetter() != null || property.getField() != null) {
|
||||
if (property.getGetter().isPresent() || property.getField().isPresent()) {
|
||||
visitGetProperty0(entity, property, mv, internalClassName);
|
||||
} else {
|
||||
mv.visitJumpInsn(GOTO, dfltLabel);
|
||||
@@ -875,10 +868,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static void visitGetProperty0(PersistentEntity<?, ?> entity, PersistentProperty<?> property,
|
||||
MethodVisitor mv, String internalClassName) {
|
||||
|
||||
Method getter = property.getGetter();
|
||||
if (property.usePropertyAccess() && getter != null) {
|
||||
property.getGetter().filter(it -> property.usePropertyAccess()).map(it -> {
|
||||
|
||||
if (generateMethodHandle(entity, getter)) {
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
// $getter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, getterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -890,35 +882,42 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
int invokeOpCode = INVOKEVIRTUAL;
|
||||
Class<?> declaringClass = getter.getDeclaringClass();
|
||||
Class<?> declaringClass = it.getDeclaringClass();
|
||||
boolean interfaceDefinition = declaringClass.isInterface();
|
||||
|
||||
if (interfaceDefinition) {
|
||||
invokeOpCode = INVOKEINTERFACE;
|
||||
}
|
||||
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(declaringClass), getter.getName(),
|
||||
String.format("()%s", signatureTypeName(getter.getReturnType())), interfaceDefinition);
|
||||
autoboxIfNeeded(getter.getReturnType(), autoboxType(getter.getReturnType()), mv);
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(declaringClass), it.getName(),
|
||||
String.format("()%s", signatureTypeName(it.getReturnType())), interfaceDefinition);
|
||||
autoboxIfNeeded(it.getReturnType(), autoboxType(it.getReturnType()), mv);
|
||||
}
|
||||
} else {
|
||||
|
||||
Field field = property.getField();
|
||||
if (generateMethodHandle(entity, field)) {
|
||||
// $fieldGetter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
|
||||
} else {
|
||||
// bean.field
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitFieldInsn(GETFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
|
||||
signatureTypeName(field.getType()));
|
||||
autoboxIfNeeded(field.getType(), autoboxType(field.getType()), mv);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}).orElseGet(() -> {
|
||||
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
// $fieldGetter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldGetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_INVOKE_METHOD_HANDLE, "invoke",
|
||||
String.format("(%s)%s", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_OBJECT)), false);
|
||||
} else {
|
||||
// bean.field
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitFieldInsn(GETFIELD, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
signatureTypeName(it.getType()));
|
||||
autoboxIfNeeded(it.getType(), autoboxType(it.getType()), mv);
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
}
|
||||
@@ -1029,7 +1028,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitLabel(propertyStackMap.get(property.getName()).label);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
|
||||
if (property.getSetter() != null || property.getField() != null) {
|
||||
if (property.getSetter().isPresent() || property.getField().isPresent()) {
|
||||
visitSetProperty0(entity, property, mv, internalClassName);
|
||||
} else {
|
||||
mv.visitJumpInsn(GOTO, dfltLabel);
|
||||
@@ -1053,10 +1052,11 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
private static void visitSetProperty0(PersistentEntity<?, ?> entity, PersistentProperty<?> property,
|
||||
MethodVisitor mv, String internalClassName) {
|
||||
|
||||
Method setter = property.getSetter();
|
||||
if (property.usePropertyAccess() && setter != null) {
|
||||
Optional<Method> setter = property.getSetter();
|
||||
|
||||
if (generateMethodHandle(entity, setter)) {
|
||||
setter.filter(it -> property.usePropertyAccess()).map(it -> {
|
||||
|
||||
if (generateMethodHandle(entity, it)) {
|
||||
// $setter.invoke(bean)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, setterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -1069,26 +1069,28 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
Class<?> parameterType = setter.getParameterTypes()[0];
|
||||
Class<?> parameterType = it.getParameterTypes()[0];
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(parameterType)));
|
||||
autoboxIfNeeded(autoboxType(parameterType), parameterType, mv);
|
||||
|
||||
int invokeOpCode = INVOKEVIRTUAL;
|
||||
Class<?> declaringClass = setter.getDeclaringClass();
|
||||
Class<?> declaringClass = it.getDeclaringClass();
|
||||
boolean interfaceDefinition = declaringClass.isInterface();
|
||||
|
||||
if (interfaceDefinition) {
|
||||
invokeOpCode = INVOKEINTERFACE;
|
||||
}
|
||||
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(setter.getDeclaringClass()), setter.getName(),
|
||||
mv.visitMethodInsn(invokeOpCode, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
String.format("(%s)V", signatureTypeName(parameterType)), interfaceDefinition);
|
||||
}
|
||||
} else {
|
||||
|
||||
Field field = property.getField();
|
||||
if (field != null) {
|
||||
if (generateSetterMethodHandle(entity, field)) {
|
||||
return null;
|
||||
|
||||
}).orElseGet(() -> {
|
||||
|
||||
property.getField().ifPresent(it -> {
|
||||
if (generateSetterMethodHandle(entity, it)) {
|
||||
// $fieldSetter.invoke(bean, object)
|
||||
mv.visitFieldInsn(GETSTATIC, internalClassName, fieldSetterName(property),
|
||||
referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE));
|
||||
@@ -1101,15 +1103,17 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
|
||||
Class<?> fieldType = field.getType();
|
||||
Class<?> fieldType = it.getType();
|
||||
|
||||
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(autoboxType(fieldType)));
|
||||
autoboxIfNeeded(autoboxType(fieldType), fieldType, mv);
|
||||
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(field.getDeclaringClass()), field.getName(),
|
||||
mv.visitFieldInsn(PUTFIELD, Type.getInternalName(it.getDeclaringClass()), it.getName(),
|
||||
signatureTypeName(fieldType));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
}
|
||||
@@ -1197,7 +1201,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
if (isAccessible(entity)) {
|
||||
|
||||
if (Modifier.isProtected(member.getModifiers()) || isDefault(member.getModifiers())) {
|
||||
if (!member.getDeclaringClass().getPackage().equals(entity.getClass().getPackage())) {
|
||||
if (!member.getDeclaringClass().getPackage().equals(entity.getType().getPackage())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -54,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, Optional<? extends Object> value) {
|
||||
accessor.setProperty(property, convertIfNecessary(value, property.getType()));
|
||||
}
|
||||
|
||||
@@ -63,7 +65,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public Object getProperty(PersistentProperty<?> property) {
|
||||
public Optional<? extends Object> getProperty(PersistentProperty<?> property) {
|
||||
return accessor.getProperty(property);
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public <T> T getProperty(PersistentProperty<?> property, Class<T> targetType) {
|
||||
public <T> Optional<T> getProperty(PersistentProperty<?> property, Class<T> targetType) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
Assert.notNull(targetType, "Target type must not be null!");
|
||||
@@ -100,8 +102,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertIfNecessary(Object source, Class<T> type) {
|
||||
return (T) (source == null ? source : type.isAssignableFrom(source.getClass()) ? source : conversionService
|
||||
.convert(source, type));
|
||||
private <T> Optional<T> convertIfNecessary(Optional<? extends Object> source, Class<T> type) {
|
||||
return source.map(it -> type.isAssignableFrom(it.getClass()) ? (T) it : conversionService.convert(it, type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -31,7 +33,7 @@ import org.springframework.util.Assert;
|
||||
public class IdPropertyIdentifierAccessor implements IdentifierAccessor {
|
||||
|
||||
private final PersistentPropertyAccessor accessor;
|
||||
private final PersistentProperty<?> idProperty;
|
||||
private final Optional<? extends PersistentProperty<?>> idProperty;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IdPropertyIdentifierAccessor} for the given {@link PersistentEntity} and
|
||||
@@ -54,7 +56,7 @@ public class IdPropertyIdentifierAccessor implements IdentifierAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
public Object getIdentifier() {
|
||||
return accessor.getProperty(idProperty);
|
||||
public Optional<? extends Object> getIdentifier() {
|
||||
return idProperty.map(it -> accessor.getProperty(it));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Exception being thrown in case an entity could not be instantiated in the process of a to-object-mapping.
|
||||
@@ -45,32 +47,33 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
* @param arguments
|
||||
* @param cause
|
||||
*/
|
||||
public MappingInstantiationException(PersistentEntity<?, ?> entity, List<Object> arguments, Exception cause) {
|
||||
public MappingInstantiationException(Optional<PersistentEntity<?, ?>> entity, List<Object> arguments,
|
||||
Exception cause) {
|
||||
this(entity, arguments, null, cause);
|
||||
}
|
||||
|
||||
private MappingInstantiationException(PersistentEntity<?, ?> entity, List<Object> arguments, String message,
|
||||
private MappingInstantiationException(Optional<PersistentEntity<?, ?>> entity, List<Object> arguments, String message,
|
||||
Exception cause) {
|
||||
|
||||
super(buildExceptionMessage(entity, arguments, message), cause);
|
||||
super(buildExceptionMessage(entity, arguments.stream(), message), cause);
|
||||
|
||||
this.entityType = entity == null ? null : entity.getType();
|
||||
this.constructor = entity == null || entity.getPersistenceConstructor() == null ? null : entity
|
||||
.getPersistenceConstructor().getConstructor();
|
||||
this.entityType = entity.map(it -> it.getType()).orElse(null);
|
||||
this.constructor = entity.flatMap(it -> it.getPersistenceConstructor()).map(c -> c.getConstructor()).orElse(null);
|
||||
this.constructorArguments = arguments;
|
||||
}
|
||||
|
||||
private static final String buildExceptionMessage(PersistentEntity<?, ?> entity, List<Object> arguments,
|
||||
private static final String buildExceptionMessage(Optional<PersistentEntity<?, ?>> entity, Stream<Object> arguments,
|
||||
String defaultMessage) {
|
||||
|
||||
if (entity == null) {
|
||||
return defaultMessage;
|
||||
}
|
||||
return entity.map(it -> {
|
||||
|
||||
PreferredConstructor<?, ?> constructor = entity.getPersistenceConstructor();
|
||||
Optional<? extends PreferredConstructor<?, ?>> constructor = it.getPersistenceConstructor();
|
||||
|
||||
return String.format(TEXT_TEMPLATE, entity.getType().getName(), constructor == null ? "NO_CONSTRUCTOR"
|
||||
: constructor.getConstructor().toString(), StringUtils.collectionToCommaDelimitedString(arguments));
|
||||
return String.format(TEXT_TEMPLATE, it.getType().getName(),
|
||||
constructor.map(c -> c.getConstructor().toString()).orElse("NO_CONSTRUCTOR"),
|
||||
String.join(",", arguments.map(Object::toString).collect(Collectors.toList())));
|
||||
|
||||
}).orElse(defaultMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,8 +81,8 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
*
|
||||
* @return the entityType
|
||||
*/
|
||||
public Class<?> getEntityType() {
|
||||
return entityType;
|
||||
public Optional<Class<?>> getEntityType() {
|
||||
return Optional.ofNullable(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,8 +90,8 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
*
|
||||
* @return the constructor
|
||||
*/
|
||||
public Constructor<?> getConstructor() {
|
||||
return constructor;
|
||||
public Optional<Constructor<?>> getConstructor() {
|
||||
return Optional.ofNullable(constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
|
||||
@@ -31,5 +33,5 @@ public interface ParameterValueProvider<P extends PersistentProperty<P>> {
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getParameterValue(Parameter<T, P> parameter);
|
||||
}
|
||||
<T> Optional<T> getParameterValue(Parameter<T, P> parameter);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
@@ -29,12 +31,12 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PersistentEntityParameterValueProvider<P extends PersistentProperty<P>> implements
|
||||
ParameterValueProvider<P> {
|
||||
public class PersistentEntityParameterValueProvider<P extends PersistentProperty<P>>
|
||||
implements ParameterValueProvider<P> {
|
||||
|
||||
private final PersistentEntity<?, P> entity;
|
||||
private final PropertyValueProvider<P> provider;
|
||||
private final Object parent;
|
||||
private final Optional<Object> parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntityParameterValueProvider} for the given {@link PersistentEntity} and
|
||||
@@ -45,10 +47,11 @@ public class PersistentEntityParameterValueProvider<P extends PersistentProperty
|
||||
* @param parent the parent object being created currently, can be {@literal null}.
|
||||
*/
|
||||
public PersistentEntityParameterValueProvider(PersistentEntity<?, P> entity, PropertyValueProvider<P> provider,
|
||||
Object parent) {
|
||||
Optional<Object> parent) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null!");
|
||||
Assert.notNull(provider, "Provider must not be null!");
|
||||
Assert.notNull(parent, "Parent must not be null!");
|
||||
|
||||
this.entity = entity;
|
||||
this.provider = provider;
|
||||
@@ -60,21 +63,18 @@ public class PersistentEntityParameterValueProvider<P extends PersistentProperty
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
public <T> Optional<T> getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor();
|
||||
PreferredConstructor<?, P> constructor = entity.getPersistenceConstructor().get();
|
||||
|
||||
if (constructor.isEnclosingClassParameter(parameter)) {
|
||||
return (T) parent;
|
||||
return (Optional<T>) parent;
|
||||
}
|
||||
|
||||
P property = entity.getPersistentProperty(parameter.getName());
|
||||
|
||||
if (property == null) {
|
||||
throw new MappingException(String.format("No property %s found on entity %s to bind constructor parameter to!",
|
||||
parameter.getName(), entity.getType()));
|
||||
}
|
||||
|
||||
return provider.getPropertyValue(property);
|
||||
return provider.getPropertyValue(parameter.getName()//
|
||||
.flatMap(it -> entity.getPersistentProperty(it))//
|
||||
.orElseThrow(() -> new MappingException(
|
||||
String.format("No property %s found on entity %s to bind constructor parameter to!", parameter.getName(),
|
||||
entity.getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mapping.model;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -37,7 +38,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private PreferredConstructor<T, P> constructor;
|
||||
private Optional<PreferredConstructor<T, P>> constructor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
|
||||
@@ -54,7 +55,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public PreferredConstructorDiscoverer(PersistentEntity<T, P> entity) {
|
||||
this(entity.getTypeInformation(), entity);
|
||||
this(entity.getTypeInformation(), Optional.ofNullable(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,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, Optional<PersistentEntity<T, P>> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
@@ -75,13 +76,13 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
this.constructor = preferredConstructor;
|
||||
this.constructor = Optional.of(preferredConstructor);
|
||||
return;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (this.constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
this.constructor = preferredConstructor;
|
||||
this.constructor = Optional.of(preferredConstructor);
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
@@ -92,13 +93,13 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
this.constructor = null;
|
||||
this.constructor = Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PreferredConstructor<T, P> buildPreferredConstructor(Constructor<?> constructor,
|
||||
TypeInformation<T> typeInformation, PersistentEntity<T, P> entity) {
|
||||
TypeInformation<T> typeInformation, Optional<PersistentEntity<T, P>> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
@@ -113,7 +114,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
Optional<String> name = Optional.ofNullable(parameterNames == null ? null : parameterNames[i]);
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
@@ -128,7 +129,7 @@ public class PreferredConstructorDiscoverer<T, P extends PersistentProperty<P>>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PreferredConstructor<T, P> getConstructor() {
|
||||
public Optional<PreferredConstructor<T, P>> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
@@ -30,5 +32,5 @@ public interface PropertyValueProvider<P extends PersistentProperty<P>> {
|
||||
* @param property will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
<T> T getPropertyValue(P property);
|
||||
<T> Optional<T> getPropertyValue(P property);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
@@ -26,7 +28,8 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P>> implements ParameterValueProvider<P> {
|
||||
public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P>>
|
||||
implements ParameterValueProvider<P> {
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
private final ParameterValueProvider<P> delegate;
|
||||
@@ -57,14 +60,15 @@ public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
public <T> Optional<T> getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
if (!parameter.hasSpelExpression()) {
|
||||
return delegate == null ? null : delegate.getParameterValue(parameter);
|
||||
return delegate.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
Object object = evaluator.evaluate(parameter.getSpelExpression());
|
||||
return object == null ? null : potentiallyConvertSpelValue(object, parameter);
|
||||
Optional<Object> object = Optional.ofNullable(evaluator.evaluate(parameter.getSpelExpression().orElse(null)));
|
||||
|
||||
return object.map(it -> potentiallyConvertSpelValue(object, parameter));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user