From a0634ce94a923473ad1a334ecd21a8de2a69becd Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 9 Apr 2018 11:43:07 +0200 Subject: [PATCH] DATAJPA-1320 - Adapt to API changes in Spring Data Commons. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JpaPersistentProperty now exposes an ….isEmbeddable(), currently used in JpaMetamodelMappingContext implementation to make sure that embeddable types are traversed when it comes to PersistentPropertyPath detection. That in turn is now used for the detection of auditing metdata, so that auditing annotations can also be used on embeddables. Lazified the decision whether a property is an association which prevents repeated annotation lookups. Related tickets: DATACMNS-1275. --- .../mapping/JpaMetamodelMappingContext.java | 14 ++++++++ .../jpa/mapping/JpaPersistentProperty.java | 7 ++++ .../mapping/JpaPersistentPropertyImpl.java | 33 +++++++++++-------- ...tamodelMappingContextIntegrationTests.java | 26 ++++++++++++++- .../JpaPersistentPropertyImplUnitTests.java | 10 +++--- 5 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java b/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java index fbf9a0c16..167d141d0 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java @@ -16,11 +16,13 @@ package org.springframework.data.jpa.mapping; import java.util.Set; +import java.util.function.Predicate; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; import org.springframework.data.jpa.provider.PersistenceProvider; +import org.springframework.data.mapping.PersistentPropertyPaths; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.Property; @@ -92,6 +94,18 @@ public class JpaMetamodelMappingContext return getMetamodelFor(type.getType()) != null; } + /** + * We customize the lookup of {@link PersistentPropertyPaths} by also traversing properties that are embeddables. + * + * @see org.springframework.data.mapping.context.AbstractMappingContext#findPersistentPropertyPaths(java.lang.Class, + * java.util.function.Predicate) + */ + @Override + public PersistentPropertyPaths findPersistentPropertyPaths(Class type, + Predicate predicate) { + return doFindPersistentPropertyPaths(type, predicate, it -> it.isEmbeddable()); + } + /** * Returns the {@link Metamodel} aware of the given type. * diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentProperty.java b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentProperty.java index 712964364..ec6e4528e 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentProperty.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentProperty.java @@ -25,4 +25,11 @@ import org.springframework.data.mapping.PersistentProperty; */ public interface JpaPersistentProperty extends PersistentProperty { + /** + * Return whether the property is considered embeddable. + * + * @return + * @since 2.1 + */ + boolean isEmbeddable(); } diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java index ac18f1437..521c8b1eb 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java @@ -75,7 +75,6 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty isIdProperty; + private final Lazy isAssociation; /** * Creates a new {@link JpaPersistentPropertyImpl} @@ -114,6 +114,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty ASSOCIATION_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent)); this.usePropertyAccess = detectPropertyAccess(); this.associationTargetType = detectAssociationTargetType(); this.updateable = detectUpdatability(); @@ -132,14 +133,16 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty> getPersistentEntityType() { - return associationTargetType != null ? Collections.singleton(associationTargetType) - : super.getPersistentEntityType(); + public Iterable> getPersistentEntityTypes() { + + return associationTargetType != null // + ? Collections.singleton(associationTargetType) // + : super.getPersistentEntityTypes(); } /* @@ -166,14 +169,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty annotationType : ASSOCIATION_ANNOTATIONS) { - if (findAnnotation(annotationType) != null) { - return true; - } - } - - return getType().isAnnotationPresent(Embeddable.class); + return isAssociation.get(); } /* @@ -221,6 +217,15 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty persistentEntity = context.getPersistentEntity(User.class); + JpaPersistentProperty property = persistentEntity.getPersistentProperty("address"); + + assertThat(property.isEmbeddable()).isTrue(); + } + + @Test // DATAJPA-1320 + public void traversesEmbeddablesButNoOtherMappingAnnotations() { + + PersistentPropertyPaths paths = // + context.findPersistentPropertyPaths(User.class, __ -> true); + + assertThat(paths.contains("address.city")).isTrue(); + + // Exists but is not selected + assertThat(context.getPersistentPropertyPath("colleagues.firstname", User.class)).isNotNull(); + assertThat(paths.contains("colleagues.firstname")).isFalse(); + } } diff --git a/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java b/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java index 04c829ff2..1ab542281 100644 --- a/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java @@ -82,13 +82,13 @@ public class JpaPersistentPropertyImplUnitTests { } @Test // DATAJPA-484 - public void considersEmbeddablePropertyAnAssociation() { - assertThat(entity.getRequiredPersistentProperty("embeddable").isAssociation(), is(true)); + public void doesNotConsiderAnEmbeddablePropertyAnAssociation() { + assertThat(entity.getRequiredPersistentProperty("embeddable").isAssociation(), is(false)); } @Test // DATAJPA-484 - public void considersEmbeddedPropertyAnAssociation() { - assertThat(entity.getRequiredPersistentProperty("embedded").isAssociation(), is(true)); + public void doesNotConsiderAnEmbeddedPropertyAnAssociation() { + assertThat(entity.getRequiredPersistentProperty("embedded").isAssociation(), is(false)); } @Test // DATAJPA-619 @@ -137,7 +137,7 @@ public class JpaPersistentPropertyImplUnitTests { assertThat(property.getType(), is(typeCompatibleWith(Api.class))); assertThat(property.getActualType(), is(typeCompatibleWith(Implementation.class))); - Iterable> entityType = property.getPersistentEntityType(); + Iterable> entityType = property.getPersistentEntityTypes(); assertThat(entityType.iterator().hasNext(), is(true)); assertThat(entityType.iterator().next(), is((TypeInformation) ClassTypeInformation.from(Implementation.class))); }