From 5f7d1ae2f2d709e5d07011301cc40fab0d25dcfa Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 15 Mar 2017 16:32:24 +0100 Subject: [PATCH] DATACMNS-867 - Overhaul of PersistentEntity API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved getRequired…(…) methods from implementations into interfaces so that implementations inherit them by default. Expanded generics declaration in PersistentEntities so that PerisistentProperty instances can be properly access from the PersistentEntity instances returned. --- .../data/mapping/PersistentEntity.java | 21 +++++++++-- .../data/mapping/PersistentProperty.java | 4 +++ .../mapping/context/PersistentEntities.java | 12 ++++--- .../model/AbstractPersistentProperty.java | 34 +++++++++--------- .../AnnotationBasedPersistentProperty.java | 36 ++++++++----------- .../mapping/model/BasicPersistentEntity.java | 16 ++------- .../support/PersistentEntityInformation.java | 2 +- 7 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/PersistentEntity.java b/src/main/java/org/springframework/data/mapping/PersistentEntity.java index 34e58cbc7..64fa4971b 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/PersistentEntity.java @@ -82,6 +82,12 @@ public interface PersistentEntity> { */ Optional

getIdProperty(); + default P getRequiredIdProperty() { + + return getIdProperty().orElseThrow( + () -> new IllegalStateException(String.format("Required identifier property not found for %s!", getType()))); + } + /** * Returns the version property of the {@link PersistentEntity}. Can be {@literal null} in case no version property is * available on the entity. @@ -94,11 +100,22 @@ public interface PersistentEntity> { * Obtains a {@link PersistentProperty} instance by name. * * @param name The name of the property - * @return the {@link PersistentProperty} or {@literal null} if it doesn't exist. + * @return the {@link PersistentProperty} or {@literal Optional#empty()} if it doesn't exist. */ Optional

getPersistentProperty(String name); - P getRequiredPersistentProperty(String name); + /** + * Returns the {@link PersistentProperty} with the given name. + * + * @param name the name of the property, must not be {@literal null} or empty. + * @return the {@link PersistentProperty} with the given name. + * @throws IllegalArgumentException in case no property with the given name exists. + */ + default P getRequiredPersistentProperty(String name) { + + return getPersistentProperty(name).orElseThrow( + () -> new IllegalArgumentException(String.format("No property %s found for type %s!", name, getType()))); + } /** * Returns the property equipped with an annotation of the given type. diff --git a/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/src/main/java/org/springframework/data/mapping/PersistentProperty.java index 666854baa..68e9afcad 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -91,6 +91,10 @@ public interface PersistentProperty

> { Optional> getAssociation(); + default Association

getRequiredAssociation() { + return getAssociation().orElseThrow(() -> new IllegalStateException("No association found!")); + } + /** * Returns whether the type of the {@link PersistentProperty} is actually to be regarded as {@link PersistentEntity} * in turn. diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java index 747a74635..395b9ca10 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.stream.Collectors; import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; @@ -30,7 +31,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @since 1.8 */ -public class PersistentEntities implements Streamable> { +public class PersistentEntities implements Streamable>> { private final Streamable> contexts; @@ -53,7 +54,7 @@ public class PersistentEntities implements Streamable> { * @param type can be {@literal null}. * @return */ - public Optional> getPersistentEntity(Class type) { + public Optional>> getPersistentEntity(Class type) { return contexts.stream()// .filter(it -> it.hasPersistentEntityFor(type))// @@ -69,7 +70,7 @@ public class PersistentEntities implements Streamable> { * @return the {@link PersistentEntity} for the given domain type. * @throws IllegalArgumentException in case no {@link PersistentEntity} can be found for the given type. */ - public PersistentEntity getRequiredPersistentEntity(Class type) { + public PersistentEntity> getRequiredPersistentEntity(Class type) { Assert.notNull(type, "Domain type must not be null!"); @@ -94,9 +95,10 @@ public class PersistentEntities implements Streamable> { * @see java.lang.Iterable#iterator() */ @Override - public Iterator> iterator() { + public Iterator>> iterator() { - return contexts.stream().> flatMap(it -> it.getPersistentEntities().stream()) + return contexts.stream() + .>> flatMap(it -> it.getPersistentEntities().stream()) .collect(Collectors.toList()).iterator(); } } diff --git a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java index e411d1d56..f1a9588b4 100644 --- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java @@ -56,8 +56,9 @@ public abstract class AbstractPersistentProperty

protected final Optional> association; private final @Getter PersistentEntity owner; private final @Getter(AccessLevel.PROTECTED) Property property; - private final SimpleTypeHolder simpleTypeHolder; private final Lazy hashCode; + private final Lazy usePropertyAccess; + private final Lazy>> entityTypeInformation; public AbstractPersistentProperty(Property property, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { @@ -67,12 +68,19 @@ public abstract class AbstractPersistentProperty

this.name = property.getName(); this.rawType = property.getType(); - this.information = PropertyPath.from(Pattern.quote(property.getName()), owner.getTypeInformation()).getTypeInformation(); + this.information = PropertyPath.from(Pattern.quote(property.getName()), owner.getTypeInformation()) + .getTypeInformation(); this.property = property; this.association = isAssociation() ? Optional.of(createAssociation()) : Optional.empty(); this.owner = owner; - this.simpleTypeHolder = simpleTypeHolder; + this.hashCode = Lazy.of(property::hashCode); + this.usePropertyAccess = Lazy + .of(() -> owner.getType().isInterface() || getField().map(it -> it.equals(CAUSE_FIELD)).orElse(false)); + this.entityTypeInformation = Lazy.of(() -> Optional.ofNullable(information.getActualType())// + .filter(it -> !simpleTypeHolder.isSimpleType(it.getType()))// + .filter(it -> !it.isCollectionLike())// + .filter(it -> !it.isMap())); } protected abstract Association

createAssociation(); @@ -124,19 +132,9 @@ public abstract class AbstractPersistentProperty

return Collections.emptySet(); } - TypeInformation candidate = getTypeInformationIfEntityCandidate(); - return candidate != null ? Collections.singleton(candidate) : Collections.emptySet(); - } - - private TypeInformation getTypeInformationIfEntityCandidate() { - - TypeInformation candidate = information.getActualType(); - - if (candidate == null || simpleTypeHolder.isSimpleType(candidate.getType())) { - return null; - } - - return candidate.isCollectionLike() || candidate.isMap() ? null : candidate; + return entityTypeInformation.get()// + .map(it -> Collections.singleton(it))// + .orElseGet(() -> Collections.emptySet()); } /* @@ -244,7 +242,7 @@ public abstract class AbstractPersistentProperty

*/ @Override public boolean isEntity() { - return !isTransient() && getTypeInformationIfEntityCandidate() != null; + return !isTransient() && entityTypeInformation.get().isPresent(); } /* @@ -284,7 +282,7 @@ public abstract class AbstractPersistentProperty

* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess() */ public boolean usePropertyAccess() { - return owner.getType().isInterface() || getField().map(it -> it.equals(CAUSE_FIELD)).orElse(false); + return usePropertyAccess.get(); } /* diff --git a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java index 9a337934a..66a9c0001 100644 --- a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java @@ -37,6 +37,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.Lazy; import org.springframework.data.util.Optionals; import org.springframework.util.Assert; @@ -55,8 +56,8 @@ public abstract class AnnotationBasedPersistentProperty

value; private final Map, Optional> annotationCache = new HashMap<>(); - private Boolean isTransient; - private boolean usePropertyAccess; + private Lazy isTransient; + private Lazy usePropertyAccess; /** * Creates a new {@link AnnotationBasedPersistentProperty}. @@ -71,9 +72,12 @@ public abstract class AnnotationBasedPersistentProperty

Type.PROPERTY.equals(it.value())) - .orElse(false); this.value = findAnnotation(Value.class); + this.usePropertyAccess = Lazy.of(() -> findPropertyOrOwnerAnnotation(AccessType.class)// + .map(it -> Type.PROPERTY.equals(it.value()))// + .orElse(super.usePropertyAccess())); + this.isTransient = Lazy.of(() -> super.isTransient() || isAnnotationPresent(Transient.class) + || isAnnotationPresent(Value.class) || isAnnotationPresent(Autowired.class)); } /** @@ -152,20 +156,13 @@ public abstract class AnnotationBasedPersistentProperty

Optionals.toStream(it)) // + .map(Object::toString) // .collect(Collectors.joining(" ")); - return builder// -// -// - + super.toString(); + return builder + super.toString(); } private Stream> getAccessors() { diff --git a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java index ef167ec91..64a2b5f8b 100644 --- a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java @@ -21,7 +21,6 @@ import lombok.RequiredArgsConstructor; import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -274,17 +273,6 @@ public class BasicPersistentEntity> implement return Optional.ofNullable(propertyCache.get(name)); } - /* - * (non-Javadoc) - * @see org.springframework.data.mapping.PersistentEntity#getRequiredPersistentProperty(java.lang.String) - */ - @Override - public P getRequiredPersistentProperty(String name) { - - return getPersistentProperty(name).orElseThrow( - () -> new IllegalArgumentException(String.format("No property %s found for type %s!", name, getType()))); - } - /* * (non-Javadoc) * @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.Class) @@ -436,8 +424,8 @@ public class BasicPersistentEntity> implement public PersistentPropertyAccessor getPropertyAccessor(Object bean) { Assert.notNull(bean, "Target bean must not be null!"); - Assert.isTrue(getType().isInstance(bean), () -> - String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName())); + Assert.isTrue(getType().isInstance(bean), + () -> String.format(TYPE_MISMATCH, bean.getClass().getName(), getType().getName())); return propertyAccessorFactory.getPropertyAccessor(this, bean); } diff --git a/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java b/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java index ad0d7dda0..b8f094ed0 100644 --- a/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/PersistentEntityInformation.java @@ -32,7 +32,7 @@ import org.springframework.data.repository.core.EntityInformation; @SuppressWarnings("unchecked") public class PersistentEntityInformation extends AbstractEntityInformation { - private final PersistentEntity persistentEntity; + private final PersistentEntity> persistentEntity; /** * Creates a new {@link PersistableEntityInformation} for the given {@link PersistentEntity}.