DATAJPA-1320 - Adapt to API changes in Spring Data Commons.
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.
This commit is contained in:
@@ -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 <T> PersistentPropertyPaths<T, JpaPersistentProperty> findPersistentPropertyPaths(Class<T> type,
|
||||
Predicate<? super JpaPersistentProperty> predicate) {
|
||||
return doFindPersistentPropertyPaths(type, predicate, it -> it.isEmbeddable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Metamodel} aware of the given type.
|
||||
*
|
||||
|
||||
@@ -25,4 +25,11 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
*/
|
||||
public interface JpaPersistentProperty extends PersistentProperty<JpaPersistentProperty> {
|
||||
|
||||
/**
|
||||
* Return whether the property is considered embeddable.
|
||||
*
|
||||
* @return
|
||||
* @since 2.1
|
||||
*/
|
||||
boolean isEmbeddable();
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
|
||||
annotations.add(OneToOne.class);
|
||||
annotations.add(ManyToMany.class);
|
||||
annotations.add(ManyToOne.class);
|
||||
annotations.add(Embedded.class);
|
||||
|
||||
ASSOCIATION_ANNOTATIONS = Collections.unmodifiableSet(annotations);
|
||||
|
||||
@@ -98,6 +97,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
|
||||
private final JpaMetamodel metamodel;
|
||||
|
||||
private final Lazy<Boolean> isIdProperty;
|
||||
private final Lazy<Boolean> isAssociation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaPersistentPropertyImpl}
|
||||
@@ -114,6 +114,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
|
||||
|
||||
Assert.notNull(metamodel, "Metamodel must not be null!");
|
||||
|
||||
this.isAssociation = Lazy.of(() -> ASSOCIATION_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent));
|
||||
this.usePropertyAccess = detectPropertyAccess();
|
||||
this.associationTargetType = detectAssociationTargetType();
|
||||
this.updateable = detectUpdatability();
|
||||
@@ -132,14 +133,16 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
|
||||
return associationTargetType != null ? associationTargetType.getType() : super.getActualType();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getPersistentEntityType()
|
||||
* @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityTypes()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<? extends TypeInformation<?>> getPersistentEntityType() {
|
||||
return associationTargetType != null ? Collections.singleton(associationTargetType)
|
||||
: super.getPersistentEntityType();
|
||||
public Iterable<? extends TypeInformation<?>> getPersistentEntityTypes() {
|
||||
|
||||
return associationTargetType != null //
|
||||
? Collections.singleton(associationTargetType) //
|
||||
: super.getPersistentEntityTypes();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -166,14 +169,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
|
||||
for (Class<? extends Annotation> 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<JpaPer
|
||||
return updateable && super.isWritable();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.mapping.JpaPersistentProperty#isEmbeddable()
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmbeddable() {
|
||||
return isAnnotationPresent(Embedded.class) || hasActualTypeAnnotation(Embeddable.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up both Spring Data's and JPA's access type definition annotations on the property or type level to determine
|
||||
* the access type to be used. Will consider property-level annotations over type-level ones, favoring the Spring Data
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -39,6 +40,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.jpa.repository.sample.CategoryRepository;
|
||||
import org.springframework.data.jpa.repository.sample.ProductRepository;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
@@ -160,4 +162,26 @@ public class JpaMetamodelMappingContextIntegrationTests {
|
||||
|
||||
assertThat(entity.getIdProperty(), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1320
|
||||
public void detectsEmbeddableProperty() {
|
||||
|
||||
JpaPersistentEntity<?> persistentEntity = context.getPersistentEntity(User.class);
|
||||
JpaPersistentProperty property = persistentEntity.getPersistentProperty("address");
|
||||
|
||||
assertThat(property.isEmbeddable()).isTrue();
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1320
|
||||
public void traversesEmbeddablesButNoOtherMappingAnnotations() {
|
||||
|
||||
PersistentPropertyPaths<User, JpaPersistentProperty> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<? extends TypeInformation<?>> entityType = property.getPersistentEntityType();
|
||||
Iterable<? extends TypeInformation<?>> entityType = property.getPersistentEntityTypes();
|
||||
assertThat(entityType.iterator().hasNext(), is(true));
|
||||
assertThat(entityType.iterator().next(), is((TypeInformation) ClassTypeInformation.from(Implementation.class)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user