DATACMNS-867 - Second draft.
This commit is contained in:
66
src/main/java/org/springframework/data/mapping/Alias.java
Normal file
66
src/main/java/org/springframework/data/mapping/Alias.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Alias {
|
||||
|
||||
public static Alias NONE = new Alias(Optional.empty());
|
||||
|
||||
Optional<? extends Object> value;
|
||||
|
||||
public static Alias of(Object alias) {
|
||||
return ofOptional(Optional.of(alias));
|
||||
}
|
||||
|
||||
public static Alias ofOptional(Optional<? extends Object> optional) {
|
||||
return optional.isPresent() ? new Alias(optional) : NONE;
|
||||
}
|
||||
|
||||
public boolean isPresentButDifferent(Alias other) {
|
||||
return isPresent() && !hasValue(other.value);
|
||||
}
|
||||
|
||||
public boolean hasValue(Object that) {
|
||||
return value.filter(it -> it.equals(that)).isPresent();
|
||||
}
|
||||
|
||||
public boolean hasSamePresentValueAs(Alias other) {
|
||||
return isPresent() && hasValue(other.value);
|
||||
}
|
||||
|
||||
public boolean isPresent() {
|
||||
return value.isPresent();
|
||||
}
|
||||
|
||||
public <T> Optional<T> mapTyped(Class<T> type) {
|
||||
return value.filter(it -> type.isInstance(it)).map(it -> type.cast(it));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value.map(Object::toString).orElse("NONE");
|
||||
}
|
||||
}
|
||||
@@ -29,5 +29,5 @@ public interface IdentifierAccessor {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Optional<? extends Object> getIdentifier();
|
||||
Optional<Object> getIdentifier();
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Optional<? extends Object> getTypeAlias();
|
||||
Alias getTypeAlias();
|
||||
|
||||
/**
|
||||
* Returns the {@link TypeInformation} backing this {@link PersistentEntity}.
|
||||
|
||||
@@ -89,7 +89,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
|
||||
Optional<String> getSpelExpression();
|
||||
|
||||
Association<P> getAssociation();
|
||||
Optional<Association<P>> getAssociation();
|
||||
|
||||
/**
|
||||
* Returns whether the type of the {@link PersistentProperty} is actually to be regarded as {@link PersistentEntity}
|
||||
@@ -199,7 +199,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
|
||||
* potentially backing field and traverse accessor methods to potentially available super types.
|
||||
*
|
||||
* @param annotationType the annotation to look up, must not be {@literal null}.
|
||||
* @return the annotation of the given type if present or {@literal null} otherwise.
|
||||
* @return the annotation of the given type.
|
||||
* @see AnnotationUtils#findAnnotation(Method, Class)
|
||||
*/
|
||||
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
|
||||
|
||||
@@ -49,7 +49,7 @@ public interface PersistentPropertyAccessor {
|
||||
* @param property must not be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
Optional<? extends Object> getProperty(PersistentProperty<?> property);
|
||||
Optional<Object> getProperty(PersistentProperty<?> property);
|
||||
|
||||
/**
|
||||
* Returns the underlying bean.
|
||||
|
||||
@@ -226,9 +226,11 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
|
||||
}
|
||||
|
||||
private static Optional<String> getValue(Annotation[] annotations) {
|
||||
return Arrays.stream(annotations).//
|
||||
filter(it -> it.annotationType() == Value.class).//
|
||||
findFirst().map(it -> ((Value) it).value());
|
||||
|
||||
return Arrays.stream(annotations)//
|
||||
.filter(it -> it.annotationType() == Value.class)//
|
||||
.findFirst().map(it -> ((Value) it).value())//
|
||||
.filter(it -> StringUtils.hasText(it));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -45,7 +46,8 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
private final TypeInformation<?> owningType;
|
||||
private final String name;
|
||||
private final TypeInformation<?> type;
|
||||
private final @Getter TypeInformation<?> typeInformation;
|
||||
private final TypeInformation<?> actualTypeInformation;
|
||||
private final boolean isCollection;
|
||||
|
||||
private PropertyPath next;
|
||||
@@ -57,7 +59,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @param owningType must not be {@literal null}.
|
||||
*/
|
||||
PropertyPath(String name, Class<?> owningType) {
|
||||
this(name, ClassTypeInformation.from(owningType), Collections.<PropertyPath> emptyList());
|
||||
this(name, ClassTypeInformation.from(owningType), Collections.<PropertyPath>emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,15 +76,13 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
Assert.notNull(base, "Perviously found properties must not be null!");
|
||||
|
||||
String propertyName = name.matches(ALL_UPPERCASE) ? name : StringUtils.uncapitalize(name);
|
||||
TypeInformation<?> propertyType = owningType.getProperty(propertyName);
|
||||
|
||||
if (propertyType == null) {
|
||||
throw new PropertyReferenceException(propertyName, owningType, base);
|
||||
}
|
||||
TypeInformation<?> propertyType = owningType.getProperty(propertyName)
|
||||
.orElseThrow(() -> new PropertyReferenceException(propertyName, owningType, base));
|
||||
|
||||
this.owningType = owningType;
|
||||
this.typeInformation = propertyType;
|
||||
this.isCollection = propertyType.isCollectionLike();
|
||||
this.type = propertyType.getActualType();
|
||||
this.actualTypeInformation = propertyType.getActualType();
|
||||
this.name = propertyName;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return this.type.getType();
|
||||
return this.actualTypeInformation.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +221,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
Assert.hasText(source, "Source must not be null or empty!");
|
||||
Assert.notNull(type, "TypeInformation must not be null or empty!");
|
||||
|
||||
List<String> iteratorSource = new ArrayList<String>();
|
||||
List<String> iteratorSource = new ArrayList<>();
|
||||
Matcher matcher = SPLITTER.matcher("_" + source);
|
||||
|
||||
while (matcher.find()) {
|
||||
@@ -231,7 +231,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
Iterator<String> parts = iteratorSource.iterator();
|
||||
|
||||
PropertyPath result = null;
|
||||
Stack<PropertyPath> current = new Stack<PropertyPath>();
|
||||
Stack<PropertyPath> current = new Stack<>();
|
||||
|
||||
while (parts.hasNext()) {
|
||||
if (result == null) {
|
||||
@@ -256,7 +256,7 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
|
||||
PropertyPath previous = base.peek();
|
||||
|
||||
PropertyPath propertyPath = create(source, previous.type, base);
|
||||
PropertyPath propertyPath = create(source, previous.typeInformation.getActualType(), base);
|
||||
previous.next = propertyPath;
|
||||
return propertyPath;
|
||||
}
|
||||
@@ -298,11 +298,11 @@ public class PropertyPath implements Streamable<PropertyPath> {
|
||||
base.get(base.size() - 1).next = current;
|
||||
}
|
||||
|
||||
List<PropertyPath> newBase = new ArrayList<PropertyPath>(base);
|
||||
List<PropertyPath> newBase = new ArrayList<>(base);
|
||||
newBase.add(current);
|
||||
|
||||
if (StringUtils.hasText(addTail)) {
|
||||
current.next = create(addTail, current.type, newBase);
|
||||
current.next = create(addTail, current.actualTypeInformation, newBase);
|
||||
}
|
||||
|
||||
return current;
|
||||
|
||||
@@ -142,7 +142,7 @@ public class PropertyReferenceException extends RuntimeException {
|
||||
*/
|
||||
private static Set<String> detectPotentialMatches(String propertyName, Class<?> type) {
|
||||
|
||||
Set<String> result = new HashSet<String>();
|
||||
Set<String> result = new HashSet<>();
|
||||
result.addAll(Arrays.asList(PropertyMatches.forField(propertyName, type).getPossibleMatches()));
|
||||
result.addAll(Arrays.asList(PropertyMatches.forProperty(propertyName, type).getPossibleMatches()));
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -42,8 +43,10 @@ import org.springframework.data.mapping.model.ClassGeneratingPropertyAccessorFac
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.MutablePersistentEntity;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -72,7 +75,8 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
|
||||
implements MappingContext<E, P>, ApplicationEventPublisherAware, InitializingBean {
|
||||
|
||||
private final Map<TypeInformation<?>, E> persistentEntities = new HashMap<TypeInformation<?>, E>();
|
||||
private final Optional<E> NONE = Optional.empty();
|
||||
private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap<>();
|
||||
private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory = new ClassGeneratingPropertyAccessorFactory();
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
@@ -132,8 +136,13 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
public Collection<E> getPersistentEntities() {
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
return Collections.unmodifiableSet(new HashSet<E>(persistentEntities.values()));
|
||||
|
||||
return persistentEntities.values().stream()//
|
||||
.flatMap(it -> Optionals.toStream(it))//
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
@@ -143,10 +152,21 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
public E getPersistentEntity(Class<?> type) {
|
||||
public Optional<E> getPersistentEntity(Class<?> type) {
|
||||
return getPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(Class<?> type) {
|
||||
|
||||
return getPersistentEntity(type).orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("Couldn't find PersistentEntity for type %s!", type)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#hasPersistentEntityFor(java.lang.Class)
|
||||
@@ -160,13 +180,15 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
public E getPersistentEntity(TypeInformation<?> type) {
|
||||
public Optional<E> getPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
try {
|
||||
|
||||
read.lock();
|
||||
E entity = persistentEntities.get(type);
|
||||
|
||||
Optional<E> entity = persistentEntities.get(type);
|
||||
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
@@ -177,7 +199,15 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
}
|
||||
|
||||
if (!shouldCreatePersistentEntityFor(type)) {
|
||||
return null;
|
||||
|
||||
try {
|
||||
write.lock();
|
||||
persistentEntities.put(type, NONE);
|
||||
} finally {
|
||||
write.unlock();
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
@@ -187,20 +217,40 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
return addPersistentEntity(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(TypeInformation<?> type) {
|
||||
|
||||
return getPersistentEntity(type)
|
||||
.orElseThrow(() -> new MappingException(String.format("Couldn't find PersistentEntity for type %s!", type)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public E getPersistentEntity(P persistentProperty) {
|
||||
public Optional<E> getPersistentEntity(P persistentProperty) {
|
||||
|
||||
if (persistentProperty == null) {
|
||||
return null;
|
||||
}
|
||||
Assert.notNull(persistentProperty, "PersistentProperty must not be null!");
|
||||
|
||||
TypeInformation<?> typeInfo = persistentProperty.getTypeInformation();
|
||||
return getPersistentEntity(typeInfo.getActualType());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getRequiredPersistentEntity(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public E getRequiredPersistentEntity(P persistentProperty) {
|
||||
|
||||
return getPersistentEntity(persistentProperty).orElseThrow(() -> new IllegalArgumentException(
|
||||
String.format("Couldn't find PersistentEntity for type %s!", persistentProperty)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.MappingContext#getPersistentPropertyPath(java.lang.Class, java.lang.String)
|
||||
@@ -248,7 +298,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
DefaultPersistentPropertyPath<P> path = DefaultPersistentPropertyPath.empty();
|
||||
Iterator<String> iterator = parts.iterator();
|
||||
E current = getPersistentEntity(type);
|
||||
E current = getRequiredPersistentEntity(type);
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
@@ -277,8 +327,11 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
Optional<P> persistentProperty = entity.getPersistentProperty(segment);
|
||||
|
||||
return persistentProperty.map(it -> Pair.of(path.append(it),
|
||||
iterator.hasNext() ? getPersistentEntity(it.getTypeInformation().getActualType()) : entity));
|
||||
return persistentProperty.map(it -> {
|
||||
|
||||
TypeInformation<?> type = it.getTypeInformation().getActualType();
|
||||
return Pair.of(path.append(it), iterator.hasNext() ? getRequiredPersistentEntity(type) : entity);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,7 +340,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(Class<?> type) {
|
||||
protected Optional<E> addPersistentEntity(Class<?> type) {
|
||||
return addPersistentEntity(ClassTypeInformation.from(type));
|
||||
}
|
||||
|
||||
@@ -297,7 +350,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected E addPersistentEntity(TypeInformation<?> typeInformation) {
|
||||
protected Optional<E> addPersistentEntity(TypeInformation<?> typeInformation) {
|
||||
|
||||
Assert.notNull(typeInformation, "TypeInformation must not be null!");
|
||||
|
||||
@@ -305,11 +358,12 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
read.lock();
|
||||
|
||||
E persistentEntity = persistentEntities.get(typeInformation);
|
||||
Optional<E> persistentEntity = persistentEntities.get(typeInformation);
|
||||
|
||||
if (persistentEntity != null) {
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
} finally {
|
||||
read.unlock();
|
||||
}
|
||||
@@ -323,7 +377,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
final E entity = createPersistentEntity(typeInformation);
|
||||
|
||||
// Eagerly cache the entity as we might have to find it during recursive lookups.
|
||||
persistentEntities.put(typeInformation, entity);
|
||||
persistentEntities.put(typeInformation, Optional.of(entity));
|
||||
|
||||
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);
|
||||
|
||||
@@ -354,7 +408,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
applicationEventPublisher.publishEvent(new MappingContextEvent<E, P>(this, entity));
|
||||
}
|
||||
|
||||
return entity;
|
||||
return Optional.of(entity);
|
||||
|
||||
} catch (BeansException e) {
|
||||
throw new MappingException(e.getMessage(), e);
|
||||
@@ -398,8 +452,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
* @param simpleTypeHolder
|
||||
* @return
|
||||
*/
|
||||
protected abstract P createPersistentProperty(Optional<Field> field, PropertyDescriptor descriptor, E owner,
|
||||
SimpleTypeHolder simpleTypeHolder);
|
||||
protected abstract P createPersistentProperty(Property property, E owner, SimpleTypeHolder simpleTypeHolder);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -471,7 +524,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
String fieldName = field.getName();
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
createAndRegisterProperty(Optional.of(field), descriptors.get(fieldName));
|
||||
createAndRegisterProperty(Property.of(field, Optional.ofNullable(descriptors.get(fieldName))));
|
||||
|
||||
this.remainingDescriptors.remove(fieldName);
|
||||
}
|
||||
@@ -486,28 +539,25 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
for (PropertyDescriptor descriptor : remainingDescriptors.values()) {
|
||||
if (PersistentPropertyFilter.INSTANCE.matches(descriptor)) {
|
||||
createAndRegisterProperty(Optional.empty(), descriptor);
|
||||
createAndRegisterProperty(Property.of(descriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndRegisterProperty(Optional<Field> field, PropertyDescriptor descriptor) {
|
||||
private void createAndRegisterProperty(Property input) {
|
||||
|
||||
P property = createPersistentProperty(field, descriptor, entity, simpleTypeHolder);
|
||||
P property = createPersistentProperty(input, entity, simpleTypeHolder);
|
||||
|
||||
if (property.isTransient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (field == null && !property.usePropertyAccess()) {
|
||||
if (!input.isFieldBacked() && !property.usePropertyAccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.addPersistentProperty(property);
|
||||
|
||||
if (property.isAssociation()) {
|
||||
entity.addAssociation(property.getAssociation());
|
||||
}
|
||||
property.getAssociation().ifPresent(it -> entity.addAssociation(it));
|
||||
|
||||
if (entity.getType().equals(property.getRawType())) {
|
||||
return;
|
||||
@@ -533,7 +583,7 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
|
||||
|
||||
static {
|
||||
|
||||
Set<PropertyMatch> matches = new HashSet<PropertyMatch>();
|
||||
Set<PropertyMatch> matches = new HashSet<>();
|
||||
matches.add(new PropertyMatch("class", null));
|
||||
matches.add(new PropertyMatch("this\\$.*", null));
|
||||
matches.add(new PropertyMatch("metaClass", "groovy.lang.MetaClass"));
|
||||
|
||||
@@ -62,7 +62,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
* @return
|
||||
*/
|
||||
public static <T extends PersistentProperty<T>> DefaultPersistentPropertyPath<T> empty() {
|
||||
return new DefaultPersistentPropertyPath<T>(Collections.<T> emptyList());
|
||||
return new DefaultPersistentPropertyPath<>(Collections.<T> emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,17 +77,17 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
|
||||
if (isEmpty()) {
|
||||
return new DefaultPersistentPropertyPath<T>(Arrays.asList(property));
|
||||
return new DefaultPersistentPropertyPath<>(Arrays.asList(property));
|
||||
}
|
||||
|
||||
Class<?> leafPropertyType = getLeafProperty().getActualType();
|
||||
Assert.isTrue(property.getOwner().getType().equals(leafPropertyType),
|
||||
String.format("Cannot append property %s to type %s!", property.getName(), leafPropertyType.getName()));
|
||||
|
||||
List<T> properties = new ArrayList<T>(this.properties);
|
||||
List<T> properties = new ArrayList<>(this.properties);
|
||||
properties.add(property);
|
||||
|
||||
return new DefaultPersistentPropertyPath<T>(properties);
|
||||
return new DefaultPersistentPropertyPath<>(properties);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,7 +125,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
? PropertyNameConverter.INSTANCE : converter);
|
||||
String delimiterToUse = delimiter == null ? "." : delimiter;
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for (T property : properties) {
|
||||
|
||||
@@ -193,7 +193,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
return this;
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<T>();
|
||||
List<T> result = new ArrayList<>();
|
||||
Iterator<T> iterator = iterator();
|
||||
|
||||
for (int i = 0; i < base.getLength(); i++) {
|
||||
@@ -204,7 +204,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
result.add(iterator.next());
|
||||
}
|
||||
|
||||
return new DefaultPersistentPropertyPath<T>(result);
|
||||
return new DefaultPersistentPropertyPath<>(result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -216,7 +216,7 @@ class DefaultPersistentPropertyPath<T extends PersistentProperty<T>> implements
|
||||
if (size <= 1) {
|
||||
return this;
|
||||
}
|
||||
return new DefaultPersistentPropertyPath<T>(properties.subList(0, size - 1));
|
||||
return new DefaultPersistentPropertyPath<>(properties.subList(0, size - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -48,7 +49,9 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(Class<?> type);
|
||||
Optional<E> getPersistentEntity(Class<?> type);
|
||||
|
||||
E getRequiredPersistentEntity(Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link MappingContext} currently contains a {@link PersistentEntity} for the type.
|
||||
@@ -67,25 +70,30 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
E getPersistentEntity(TypeInformation<?> type);
|
||||
Optional<E> getPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
E getRequiredPersistentEntity(TypeInformation<?> type);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param persistentProperty
|
||||
* @param persistentProperty must not be {@literal null}.
|
||||
* @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or null if no
|
||||
* {@link PersistentEntity} exists for it or the {@link PersistentProperty} does not refer to an entity (the
|
||||
* type of the property is considered simple see
|
||||
* {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}).
|
||||
*/
|
||||
E getPersistentEntity(P persistentProperty);
|
||||
Optional<E> getPersistentEntity(P persistentProperty);
|
||||
|
||||
E getRequiredPersistentEntity(P persistentProperty);
|
||||
|
||||
/**
|
||||
* Returns all {@link PersistentProperty}s for the given path expression based on the given {@link PropertyPath}.
|
||||
*
|
||||
* @param propertyPath must not be {@literal null}.
|
||||
* @return the {@link PersistentPropertyPath} representing the given {@link PropertyPath}.
|
||||
* @throws InvalidPersistentPropertyPath in case not all of the segments of the given {@link PropertyPath} can be resolved.
|
||||
* @throws InvalidPersistentPropertyPath in case not all of the segments of the given {@link PropertyPath} can be
|
||||
* resolved.
|
||||
*/
|
||||
PersistentPropertyPath<P> getPersistentPropertyPath(PropertyPath propertyPath);
|
||||
|
||||
@@ -100,10 +108,12 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
|
||||
PersistentPropertyPath<P> getPersistentPropertyPath(String propertyPath, Class<?> type);
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentPropertyPath} for the resolvable part of the given {@link InvalidPersistentPropertyPath}.
|
||||
* Returns the {@link PersistentPropertyPath} for the resolvable part of the given
|
||||
* {@link InvalidPersistentPropertyPath}.
|
||||
*
|
||||
* @param invalidPath must not be {@literal null}.
|
||||
* @return the {@link PersistentPropertyPath} for the resolvable part of the given {@link InvalidPersistentPropertyPath}.
|
||||
* @return the {@link PersistentPropertyPath} for the resolvable part of the given
|
||||
* {@link InvalidPersistentPropertyPath}.
|
||||
* @since 1.11
|
||||
*/
|
||||
PersistentPropertyPath<P> getPersistentPropertyPath(InvalidPersistentPropertyPath invalidPath);
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
@@ -69,19 +72,25 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
@Override
|
||||
protected IsNewStrategy doGetIsNewStrategy(Class<?> type) {
|
||||
|
||||
PersistentEntity<?, ?> entity = context.getPersistentEntity(type);
|
||||
return context.getPersistentEntity(type)//
|
||||
.flatMap(it -> foo(it))//
|
||||
.orElseThrow(() -> new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type)));
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
private static Optional<IsNewStrategy> foo(PersistentEntity<?, ?> entity) {
|
||||
|
||||
if (entity.hasVersionProperty()) {
|
||||
return new PropertyIsNullOrZeroNumberIsNewStrategy(entity.getVersionProperty().get());
|
||||
|
||||
return entity.getVersionProperty().map(it -> PersistentPropertyInspectingIsNewStrategy.of(it,
|
||||
MappingContextIsNewStrategyFactory::propertyIsNullOrZeroNumber));
|
||||
|
||||
} else if (entity.hasIdProperty()) {
|
||||
return new PropertyIsNullIsNewStrategy(entity.getIdProperty().get());
|
||||
} else {
|
||||
throw new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type));
|
||||
|
||||
return entity.getIdProperty().map(
|
||||
it -> PersistentPropertyInspectingIsNewStrategy.of(it, MappingContextIsNewStrategyFactory::propertyIsNull));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,19 +99,11 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static abstract class PersistentPropertyInspectingIsNewStrategy implements IsNewStrategy {
|
||||
@RequiredArgsConstructor(staticName = "of")
|
||||
static class PersistentPropertyInspectingIsNewStrategy implements IsNewStrategy {
|
||||
|
||||
private final PersistentProperty<?> property;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentPropertyInspectingIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PersistentPropertyInspectingIsNewStrategy(PersistentProperty<?> property) {
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
this.property = property;
|
||||
}
|
||||
private final @NonNull PersistentProperty<?> property;
|
||||
private final @NonNull Function<Optional<Object>, Boolean> isNew;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -111,80 +112,26 @@ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupp
|
||||
@Override
|
||||
public boolean isNew(Optional<? extends Object> entity) {
|
||||
|
||||
return entity.map(it -> {
|
||||
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(it);
|
||||
Object propertyValue = accessor.getProperty(property);
|
||||
|
||||
return decideIsNew(propertyValue);
|
||||
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
protected abstract boolean decideIsNew(Object property);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that does a check against {@literal null} for the given value and considers the object new if
|
||||
* the value given is {@literal null}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullIsNewStrategy} using the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
return property == null;
|
||||
return entity//
|
||||
.map(it -> isNew.apply(property.getOwner().getPropertyAccessor(it).getProperty(property)))//
|
||||
.orElse(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IsNewStrategy} that considers property values of {@literal null} or 0 (in case of a {@link Number})
|
||||
* implementation as indicators for the new state.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class PropertyIsNullOrZeroNumberIsNewStrategy extends PersistentPropertyInspectingIsNewStrategy {
|
||||
private static boolean propertyIsNull(Optional<Object> it) {
|
||||
return !it.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyIsNullOrZeroNumberIsNewStrategy} instance using the given {@link PersistentProperty}
|
||||
* .
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
*/
|
||||
public PropertyIsNullOrZeroNumberIsNewStrategy(PersistentProperty<?> property) {
|
||||
super(property);
|
||||
}
|
||||
private static boolean propertyIsNullOrZeroNumber(Optional<Object> it) {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory.PersistentPropertyInspectingIsNewStrategy#decideIsNew(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected boolean decideIsNew(Object property) {
|
||||
return it.map(value -> {
|
||||
|
||||
if (property == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(property instanceof Number)) {
|
||||
if (!(value instanceof Number)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((Number) property).longValue() == 0;
|
||||
}
|
||||
return ((Number) value).longValue() == 0;
|
||||
|
||||
}).orElse(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -32,9 +30,9 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
public class PersistentEntities implements Iterable<PersistentEntity<?, ?>> {
|
||||
public class PersistentEntities implements Streamable<PersistentEntity<?, ?>> {
|
||||
|
||||
private final Iterable<? extends MappingContext<?, ?>> contexts;
|
||||
private final Streamable<? extends MappingContext<?, ?>> contexts;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PersistentEntities} for the given {@link MappingContext}s.
|
||||
@@ -44,7 +42,7 @@ public class PersistentEntities implements Iterable<PersistentEntity<?, ?>> {
|
||||
public PersistentEntities(Iterable<? extends MappingContext<?, ?>> contexts) {
|
||||
|
||||
Assert.notNull(contexts, "MappingContexts must not be null!");
|
||||
this.contexts = contexts;
|
||||
this.contexts = Streamable.of(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,16 +53,11 @@ public class PersistentEntities implements Iterable<PersistentEntity<?, ?>> {
|
||||
* @param type can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public PersistentEntity<?, ?> getPersistentEntity(Class<?> type) {
|
||||
public Optional<PersistentEntity<?, ?>> getPersistentEntity(Class<?> type) {
|
||||
|
||||
for (MappingContext<?, ?> context : contexts) {
|
||||
|
||||
if (context.hasPersistentEntityFor(type)) {
|
||||
return context.getPersistentEntity(type);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return contexts.stream()//
|
||||
.filter(it -> it.hasPersistentEntityFor(type))//
|
||||
.findFirst().map(it -> it.getRequiredPersistentEntity(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,15 +65,11 @@ public class PersistentEntities implements Iterable<PersistentEntity<?, ?>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<TypeInformation<?>> getManagedTypes() {
|
||||
public Streamable<TypeInformation<?>> getManagedTypes() {
|
||||
|
||||
Set<TypeInformation<?>> informations = new HashSet<TypeInformation<?>>();
|
||||
|
||||
for (MappingContext<?, ?> context : contexts) {
|
||||
informations.addAll(context.getManagedTypes());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(informations);
|
||||
return Streamable.of(contexts.stream()//
|
||||
.flatMap(it -> it.getManagedTypes().stream())//
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,12 +79,7 @@ public class PersistentEntities implements Iterable<PersistentEntity<?, ?>> {
|
||||
@Override
|
||||
public Iterator<PersistentEntity<?, ?>> iterator() {
|
||||
|
||||
List<PersistentEntity<?, ?>> entities = new ArrayList<PersistentEntity<?, ?>>();
|
||||
|
||||
for (MappingContext<?, ?> context : contexts) {
|
||||
entities.addAll(context.getPersistentEntities());
|
||||
}
|
||||
|
||||
return entities.iterator();
|
||||
return contexts.stream().<PersistentEntity<?, ?>>flatMap(it -> it.getPersistentEntities().stream())
|
||||
.collect(Collectors.toList()).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
@@ -26,6 +28,8 @@ import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -46,43 +50,33 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
}
|
||||
|
||||
protected final String name;
|
||||
protected final Optional<PropertyDescriptor> propertyDescriptor;
|
||||
protected final TypeInformation<?> information;
|
||||
protected final Class<?> rawType;
|
||||
protected final Optional<Field> field;
|
||||
protected final Association<P> association;
|
||||
protected final PersistentEntity<?, P> owner;
|
||||
protected final Optional<Association<P>> association;
|
||||
private final @Getter PersistentEntity<?, P> owner;
|
||||
private final @Getter(AccessLevel.PROTECTED) Property property;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
private final int hashCode;
|
||||
private final Lazy<Integer> hashCode;
|
||||
|
||||
public AbstractPersistentProperty(Optional<Field> field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
public AbstractPersistentProperty(Property property, 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.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 = Optional.ofNullable(propertyDescriptor);
|
||||
this.field = field;
|
||||
this.association = isAssociation() ? createAssociation() : null;
|
||||
this.name = property.getName();
|
||||
this.rawType = property.getRawType();
|
||||
|
||||
this.information = PropertyPath.from(property.getName(), owner.getTypeInformation()).getTypeInformation();
|
||||
this.property = property;
|
||||
this.association = isAssociation() ? Optional.of(createAssociation()) : Optional.empty();
|
||||
this.owner = owner;
|
||||
this.simpleTypeHolder = simpleTypeHolder;
|
||||
this.hashCode = this.field == null ? this.propertyDescriptor.hashCode() : this.field.hashCode();
|
||||
this.hashCode = Lazy.of(() -> property.hashCode());
|
||||
}
|
||||
|
||||
protected abstract Association<P> createAssociation();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getOwner()
|
||||
*/
|
||||
@Override
|
||||
public PersistentEntity<?, P> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getName()
|
||||
@@ -131,7 +125,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
}
|
||||
|
||||
TypeInformation<?> candidate = getTypeInformationIfEntityCandidate();
|
||||
return candidate != null ? Collections.singleton(candidate) : Collections.<TypeInformation<?>> emptySet();
|
||||
return candidate != null ? Collections.singleton(candidate) : Collections.<TypeInformation<?>>emptySet();
|
||||
}
|
||||
|
||||
private TypeInformation<?> getTypeInformationIfEntityCandidate() {
|
||||
@@ -151,8 +145,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Optional<Method> getGetter() {
|
||||
return propertyDescriptor.map(it -> it.getReadMethod())//
|
||||
.filter(it -> rawType.isAssignableFrom(it.getReturnType()));
|
||||
return property.getGetter();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -161,8 +154,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Optional<Method> getSetter() {
|
||||
return propertyDescriptor.map(it -> it.getWriteMethod())//
|
||||
.filter(it -> it.getParameterTypes()[0].isAssignableFrom(rawType));
|
||||
return property.getSetter();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,7 +163,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Optional<Field> getField() {
|
||||
return field;
|
||||
return property.getField();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -215,7 +207,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getAssociation()
|
||||
*/
|
||||
@Override
|
||||
public Association<P> getAssociation() {
|
||||
public Optional<Association<P>> getAssociation() {
|
||||
return association;
|
||||
}
|
||||
|
||||
@@ -266,8 +258,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeInformation<?> componentType = information.getComponentType();
|
||||
return componentType == null ? null : componentType.getType();
|
||||
return information.getRequiredComponentType().getType();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -276,7 +267,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getMapValueType() {
|
||||
return isMap() ? information.getMapValueType().getType() : null;
|
||||
return isMap() ? information.getMapValueType().map(it -> it.getType()).orElse(null) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -293,7 +284,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess()
|
||||
*/
|
||||
public boolean usePropertyAccess() {
|
||||
return owner.getType().isInterface() || CAUSE_FIELD.equals(getField());
|
||||
return owner.getType().isInterface() || getField().map(it -> it.equals(CAUSE_FIELD)).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -313,7 +304,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
|
||||
AbstractPersistentProperty<?> that = (AbstractPersistentProperty<?>) obj;
|
||||
|
||||
return this.field == null ? this.propertyDescriptor.equals(that.propertyDescriptor) : this.field.equals(that.field);
|
||||
return this.property.equals(that.property);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -322,7 +313,7 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hashCode;
|
||||
return this.hashCode.get();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -331,8 +322,6 @@ public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return field.map(Object::toString)//
|
||||
.orElseGet(() -> propertyDescriptor.map(Object::toString)//
|
||||
.orElseThrow(() -> new IllegalStateException("Either Field or PropertyDescriptor has to be present!")));
|
||||
return property.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
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.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -63,15 +61,15 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
* Creates a new {@link AnnotationBasedPersistentProperty}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param propertyDescriptor can be {@literal null}.
|
||||
* @param propertyDescriptor must not be {@literal null}.
|
||||
* @param owner must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationBasedPersistentProperty(Optional<Field> field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
public AnnotationBasedPersistentProperty(Property property, PersistentEntity<?, P> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
super(property, owner, simpleTypeHolder);
|
||||
|
||||
populateAnnotationCache(field);
|
||||
populateAnnotationCache(property);
|
||||
|
||||
this.usePropertyAccess = findPropertyOrOwnerAnnotation(AccessType.class).map(it -> Type.PROPERTY.equals(it.value()))
|
||||
.orElse(false);
|
||||
@@ -85,9 +83,9 @@ 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(Optional<Field> field) {
|
||||
private final void populateAnnotationCache(Property property) {
|
||||
|
||||
Optionals.toStream(getGetter(), getSetter()).forEach(it -> {
|
||||
Optionals.toStream(property.getGetter(), property.getSetter()).forEach(it -> {
|
||||
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
@@ -102,7 +100,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
}
|
||||
});
|
||||
|
||||
field.ifPresent(it -> {
|
||||
property.getField().ifPresent(it -> {
|
||||
|
||||
for (Annotation annotation : it.getAnnotations()) {
|
||||
|
||||
@@ -218,10 +216,11 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
return (Optional<A>) annotationCache.get(annotationType);
|
||||
}
|
||||
|
||||
return cacheAndReturn(annotationType, getAccessors()//
|
||||
.map(it -> it.map(inner -> AnnotatedElementUtils.findMergedAnnotation(inner, annotationType)))//
|
||||
.flatMap(it -> Optionals.toStream(it))//
|
||||
.findFirst());
|
||||
return cacheAndReturn(annotationType,
|
||||
getAccessors()//
|
||||
.map(it -> it.map(inner -> AnnotatedElementUtils.findMergedAnnotation(inner, annotationType)))//
|
||||
.flatMap(it -> Optionals.toStream(it))//
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -232,7 +231,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
public <A extends Annotation> Optional<A> findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
|
||||
Optional<A> annotation = findAnnotation(annotationType);
|
||||
return annotation.isPresent() ? annotation : owner.findAnnotation(annotationType);
|
||||
return annotation.isPresent() ? annotation : getOwner().findAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,7 +276,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
public String toString() {
|
||||
|
||||
if (annotationCache.isEmpty()) {
|
||||
populateAnnotationCache(field);
|
||||
populateAnnotationCache(getProperty());
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder().append(annotationCache.values().stream()//
|
||||
@@ -289,6 +288,6 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
|
||||
}
|
||||
|
||||
private Stream<Optional<? extends AnnotatedElement>> getAccessors() {
|
||||
return Arrays.<Optional<? extends AnnotatedElement>> asList(getGetter(), getSetter(), getField()).stream();
|
||||
return Arrays.<Optional<? extends AnnotatedElement>>asList(getGetter(), getSetter(), getField()).stream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.data.annotation.TypeAlias;
|
||||
import org.springframework.data.mapping.Alias;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
@@ -79,7 +80,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
private Optional<P> versionProperty = Optional.empty();
|
||||
private PersistentPropertyAccessorFactory propertyAccessorFactory;
|
||||
|
||||
private final Lazy<Optional<? extends Object>> typeAlias;
|
||||
private final Lazy<Alias> typeAlias;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
|
||||
@@ -106,16 +107,17 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
this.properties = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
this.constructor = new PreferredConstructorDiscoverer<>(this).getConstructor();
|
||||
this.associations = comparator.<Set<Association<P>>> map(it -> new TreeSet<>(new AssociationComparator<>(it)))
|
||||
.orElse(new HashSet<>());
|
||||
this.associations = comparator.<Set<Association<P>>>map(it -> new TreeSet<>(new AssociationComparator<>(it)))
|
||||
.orElseGet(() -> new HashSet<>());
|
||||
|
||||
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)));
|
||||
this.typeAlias = Lazy.of(() -> Alias
|
||||
.ofOptional(Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(getType(), TypeAlias.class))//
|
||||
.map(TypeAlias::value)//
|
||||
.filter(it -> StringUtils.hasText(it))));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -304,7 +306,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getTypeAlias()
|
||||
*/
|
||||
public Optional<? extends Object> getTypeAlias() {
|
||||
public Alias getTypeAlias() {
|
||||
return typeAlias.get();
|
||||
}
|
||||
|
||||
@@ -441,7 +443,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
@Override
|
||||
public Optional<? extends Object> getIdentifier() {
|
||||
public Optional<Object> getIdentifier() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class BeanWrapper<T> implements PersistentPropertyAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
public Optional<? extends Object> getProperty(PersistentProperty<?> property) {
|
||||
public Optional<Object> getProperty(PersistentProperty<?> property) {
|
||||
return getProperty(property, property.getType());
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ enum BeanWrapperPropertyAccessorFactory implements PersistentPropertyAccessorFac
|
||||
*/
|
||||
@Override
|
||||
public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity<?, ?> entity, Object bean) {
|
||||
return new BeanWrapper<Object>(bean);
|
||||
return new BeanWrapper<>(bean);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -53,7 +53,7 @@ public class CamelCaseSplittingFieldNamingStrategy implements FieldNamingStrateg
|
||||
public String getFieldName(PersistentProperty<?> property) {
|
||||
|
||||
List<String> parts = ParsingUtils.splitCamelCaseToLower(property.getName());
|
||||
List<String> result = new ArrayList<String>();
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for (String part : parts) {
|
||||
|
||||
|
||||
@@ -64,9 +64,6 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccessorFactory {
|
||||
|
||||
private static final boolean IS_JAVA_7_OR_BETTER = org.springframework.util.ClassUtils
|
||||
.isPresent("java.lang.invoke.MethodHandle", ClassGeneratingPropertyAccessorFactory.class.getClassLoader());
|
||||
|
||||
private volatile Map<TypeInformation<?>, Class<PersistentPropertyAccessor>> propertyAccessorClasses = new HashMap<TypeInformation<?>, Class<PersistentPropertyAccessor>>(
|
||||
32);
|
||||
|
||||
@@ -103,15 +100,11 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
|
||||
if (!IS_JAVA_7_OR_BETTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entity.getType().getClassLoader() == null || entity.getType().getPackage().getName().startsWith("java")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Set<Integer> hashCodes = new HashSet<Integer>();
|
||||
final Set<Integer> hashCodes = new HashSet<>();
|
||||
final AtomicInteger propertyCount = new AtomicInteger();
|
||||
|
||||
entity.doWithProperties(new SimplePropertyHandler() {
|
||||
@@ -821,7 +814,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
int[] hashes = new int[propertyStackMap.size()];
|
||||
Label[] switchJumpLabels = new Label[propertyStackMap.size()];
|
||||
List<PropertyStackAddress> stackmap = new ArrayList<PropertyStackAddress>(propertyStackMap.values());
|
||||
List<PropertyStackAddress> stackmap = new ArrayList<>(propertyStackMap.values());
|
||||
Collections.sort(stackmap);
|
||||
|
||||
for (int i = 0; i < stackmap.size(); i++) {
|
||||
@@ -983,8 +976,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
mv.visitLocalVariable(THIS_REF, referenceName(internalClassName), null, l0, l1, 0);
|
||||
mv.visitLocalVariable("property", "Lorg/springframework/data/mapping/PersistentProperty;",
|
||||
"Lorg/springframework/data/mapping/PersistentProperty<*>;", l0, l1, 1);
|
||||
mv.visitLocalVariable("optional", referenceName(JAVA_UTIL_OPTIONAL),
|
||||
"Ljava/util/Optional<+Ljava/lang/Object;>;", l0, l1, 2);
|
||||
mv.visitLocalVariable("optional", referenceName(JAVA_UTIL_OPTIONAL), "Ljava/util/Optional<+Ljava/lang/Object;>;",
|
||||
l0, l1, 2);
|
||||
|
||||
if (isAccessible(entity)) {
|
||||
mv.visitLocalVariable(BEAN_FIELD, referenceName(entity.getType()), null, l0, l1, 3);
|
||||
@@ -1022,7 +1015,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
|
||||
int[] hashes = new int[propertyStackMap.size()];
|
||||
Label[] switchJumpLabels = new Label[propertyStackMap.size()];
|
||||
List<PropertyStackAddress> stackmap = new ArrayList<PropertyStackAddress>(propertyStackMap.values());
|
||||
List<PropertyStackAddress> stackmap = new ArrayList<>(propertyStackMap.values());
|
||||
Collections.sort(stackmap);
|
||||
|
||||
for (int i = 0; i < stackmap.size(); i++) {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ConvertingPropertyAccessor implements PersistentPropertyAccessor {
|
||||
* @see org.springframework.data.mapping.PersistentPropertyAccessor#getProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public Optional<? extends Object> getProperty(PersistentProperty<?> property) {
|
||||
public Optional<Object> getProperty(PersistentProperty<?> property) {
|
||||
return accessor.getProperty(property);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public class IdPropertyIdentifierAccessor implements IdentifierAccessor {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.keyvalue.core.IdentifierAccessor#getIdentifier()
|
||||
*/
|
||||
public Optional<? extends Object> getIdentifier() {
|
||||
return idProperty.map(it -> accessor.getProperty(it));
|
||||
public Optional<Object> getIdentifier() {
|
||||
return idProperty.flatMap(it -> accessor.getProperty(it));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class Property {
|
||||
|
||||
private final @Getter Optional<Field> field;
|
||||
private final Optional<PropertyDescriptor> descriptor;
|
||||
|
||||
private final Lazy<Class<?>> rawType;
|
||||
private final Lazy<Integer> hashCode;
|
||||
|
||||
private Property(Optional<Field> field, Optional<PropertyDescriptor> descriptor) {
|
||||
|
||||
this.field = field;
|
||||
this.descriptor = descriptor;
|
||||
this.hashCode = Lazy.of(() -> computeHashCode());
|
||||
this.rawType = Lazy
|
||||
.of(() -> field.<Class<?>>map(Field::getType).orElseGet(() -> descriptor.map(it -> it.getPropertyType())//
|
||||
.orElseThrow(() -> new IllegalStateException())));
|
||||
}
|
||||
|
||||
public static Property of(Field field) {
|
||||
return of(field, Optional.empty());
|
||||
}
|
||||
|
||||
public static Property of(Field field, Optional<PropertyDescriptor> descriptor) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
|
||||
return new Property(Optional.of(field), descriptor);
|
||||
}
|
||||
|
||||
public static Property of(PropertyDescriptor descriptor) {
|
||||
|
||||
Assert.notNull(descriptor, "PropertyDescriptor must not be null!");
|
||||
return new Property(Optional.empty(), Optional.of(descriptor));
|
||||
}
|
||||
|
||||
public boolean isFieldBacked() {
|
||||
return field.isPresent();
|
||||
}
|
||||
|
||||
public Optional<Method> getGetter() {
|
||||
return descriptor.map(it -> it.getReadMethod())//
|
||||
.filter(it -> getRawType().isAssignableFrom(it.getReturnType()));
|
||||
}
|
||||
|
||||
public Optional<Method> getSetter() {
|
||||
return descriptor.map(it -> it.getWriteMethod())//
|
||||
.filter(it -> it.getParameterTypes()[0].isAssignableFrom(getRawType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return field.map(Field::getName).orElseGet(() -> descriptor.map(it -> it.getName())//
|
||||
.orElseThrow(() -> new IllegalStateException()));
|
||||
}
|
||||
|
||||
public Class<?> getRawType() {
|
||||
return rawType.get();
|
||||
}
|
||||
|
||||
private int computeHashCode() {
|
||||
|
||||
return this.field.map(it -> it.hashCode())
|
||||
.orElseGet(() -> this.descriptor.map(it -> it.hashCode()).orElseThrow(() -> new IllegalStateException()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property that = (Property) obj;
|
||||
|
||||
return this.field.isPresent() ? this.field.equals(that.field) : this.descriptor.equals(that.descriptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return field.map(Object::toString)
|
||||
.orElseGet(() -> descriptor.map(Object::toString).orElseThrow(() -> new IllegalStateException()));
|
||||
}
|
||||
}
|
||||
@@ -62,13 +62,10 @@ public class SpELExpressionParameterValueProvider<P extends PersistentProperty<P
|
||||
*/
|
||||
public <T> Optional<T> getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
if (!parameter.hasSpelExpression()) {
|
||||
return delegate.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
Optional<Object> object = Optional.ofNullable(evaluator.evaluate(parameter.getSpelExpression().orElse(null)));
|
||||
|
||||
return object.map(it -> potentiallyConvertSpelValue(object, parameter));
|
||||
return parameter.getSpelExpression()//
|
||||
.map(it -> Optional.ofNullable(evaluator.evaluate(it))//
|
||||
.map(result -> potentiallyConvertSpelValue(result, parameter)))
|
||||
.orElseGet(() -> delegate.getParameterValue(parameter));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user