DATACMNS-1318 - Allow inspection of a reference's ultimate target entity.
We now expose what type or PersistentEntity an association points to by trying to match the association's type to identifier types to entities. In case multiple matches are found, we require the user to explicitly declare the target type via @Reference. Introduced PersistentEntities.of(…) for convenience.
This commit is contained in:
@@ -25,6 +25,9 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
|
||||
/**
|
||||
@@ -72,10 +75,100 @@ public class PersistentEntitiesUnitTests {
|
||||
assertThat(entities.getManagedTypes()).contains(ClassTypeInformation.from(Sample.class));
|
||||
|
||||
assertThat(entities.getPersistentEntity(Sample.class)).hasValueSatisfying(it -> assertThat(entities).contains(it));
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1318
|
||||
public void detectsReferredToEntity() {
|
||||
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
context.getPersistentEntity(Sample.class);
|
||||
|
||||
SamplePersistentProperty property = context.getRequiredPersistentEntity(WithReference.class)//
|
||||
.getPersistentProperty("sampleId");
|
||||
|
||||
PersistentEntity<?, ?> referredToEntity = PersistentEntities.of(context).getEntityUltimatelyReferredToBy(property);
|
||||
|
||||
assertThat(referredToEntity).isNotNull();
|
||||
assertThat(referredToEntity.getType()).isEqualTo(Sample.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1318
|
||||
public void rejectsAmbiguousIdentifierType() {
|
||||
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
context.getPersistentEntity(FirstWithLongId.class);
|
||||
context.getPersistentEntity(SecondWithLongId.class);
|
||||
|
||||
SamplePersistentProperty property = context.getRequiredPersistentEntity(WithReference.class) //
|
||||
.getPersistentProperty("longId");
|
||||
|
||||
PersistentEntities entities = PersistentEntities.of(context);
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException.class)//
|
||||
.isThrownBy(() -> entities.getEntityUltimatelyReferredToBy(property)) //
|
||||
.withMessageContaining(FirstWithLongId.class.getName()) //
|
||||
.withMessageContaining(SecondWithLongId.class.getName()) //
|
||||
.withMessageContaining(Reference.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1318
|
||||
public void allowsExplicitlyQualifiedReference() {
|
||||
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
context.getPersistentEntity(FirstWithLongId.class);
|
||||
context.getPersistentEntity(SecondWithLongId.class);
|
||||
|
||||
SamplePersistentProperty property = context.getRequiredPersistentEntity(WithReference.class) //
|
||||
.getPersistentProperty("qualifiedLongId");
|
||||
|
||||
PersistentEntity<?, ?> entity = PersistentEntities.of(context).getEntityUltimatelyReferredToBy(property);
|
||||
|
||||
assertThat(entity).isNotNull();
|
||||
assertThat(entity.getType()).isEqualTo(FirstWithLongId.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1318
|
||||
public void allowsGenericReference() {
|
||||
|
||||
SampleMappingContext context = new SampleMappingContext();
|
||||
context.getPersistentEntity(FirstWithGenericId.class);
|
||||
context.getPersistentEntity(SecondWithGenericId.class);
|
||||
|
||||
SamplePersistentProperty property = context.getRequiredPersistentEntity(WithReference.class) //
|
||||
.getPersistentProperty("generic");
|
||||
|
||||
PersistentEntity<?, ?> entity = PersistentEntities.of(context).getEntityUltimatelyReferredToBy(property);
|
||||
|
||||
assertThat(entity).isNotNull();
|
||||
assertThat(entity.getType()).isEqualTo(SecondWithGenericId.class);
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
@Id String id;
|
||||
}
|
||||
|
||||
static class WithReference {
|
||||
@Reference String sampleId;
|
||||
@Reference Long longId;
|
||||
@Reference(FirstWithLongId.class) Long qualifiedLongId;
|
||||
@Reference Identifier<SecondWithGenericId> generic;
|
||||
}
|
||||
|
||||
static class FirstWithLongId {
|
||||
@Id Long id;
|
||||
}
|
||||
|
||||
static class SecondWithLongId {
|
||||
@Id Long id;
|
||||
}
|
||||
|
||||
static class FirstWithGenericId {
|
||||
@Id Identifier<FirstWithGenericId> id;
|
||||
}
|
||||
|
||||
static class SecondWithGenericId {
|
||||
@Id Identifier<SecondWithGenericId> id;
|
||||
}
|
||||
|
||||
interface Identifier<T> {}
|
||||
}
|
||||
|
||||
@@ -368,6 +368,11 @@ public class AbstractPersistentPropertyUnitTests {
|
||||
public <A extends Annotation> A findPropertyOrOwnerAnnotation(Class<A> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAssociationTargetType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class Sample {
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.data.annotation.AccessType;
|
||||
import org.springframework.data.annotation.AccessType.Type;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -239,6 +241,14 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
assertThatThrownBy(() -> property.getRequiredAnnotation(Transient.class)).isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1318
|
||||
public void detectsUltimateAssociationTargetClass() {
|
||||
|
||||
Stream.of("toSample", "toSample2", "sample", "withoutAnnotation").forEach(it -> {
|
||||
assertThat(getProperty(WithReferences.class, it).getAssociationTargetType()).isEqualTo(Sample.class);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Class<? extends Annotation>, Annotation> getAnnotationCache(SamplePersistentProperty property) {
|
||||
return (Map<Class<? extends Annotation>, Annotation>) ReflectionTestUtils.getField(property, "annotationCache");
|
||||
@@ -410,4 +420,12 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
@interface CustomReadOnly {
|
||||
|
||||
}
|
||||
|
||||
static class WithReferences {
|
||||
|
||||
@Reference(to = Sample.class) String toSample;
|
||||
@Reference(Sample.class) String toSample2;
|
||||
@Reference Sample sample;
|
||||
Sample withoutAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user