From 14fbc11f00844e71866a91882ee8d4dfac5459fa Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 8 Aug 2018 13:11:34 +0200 Subject: [PATCH] DATACMNS-1366 - Introduce PersistentEntity.requiresPropertyPopulation(). The newly introduced method indicates whether any properties have to be populated to create instances of the entity. This is useful for objects that are completely initialized through their constructors as converters then can avoid iterating over all properties just to find out none of them have to be populated. --- .../data/mapping/PersistentEntity.java | 9 ++++ .../mapping/model/BasicPersistentEntity.java | 12 +++++ .../model/BasicPersistentEntityUnitTests.java | 45 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/main/java/org/springframework/data/mapping/PersistentEntity.java b/src/main/java/org/springframework/data/mapping/PersistentEntity.java index a919e39fd..94ddc102f 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/PersistentEntity.java @@ -316,4 +316,13 @@ public interface PersistentEntity> extends It * @since 2.1 */ boolean isImmutable(); + + /** + * Returns whether the entity needs properties to be populated, i.e. if any property exists that's not initialized by + * the constructor. + * + * @return + * @since 2.1 + */ + boolean requiresPropertyPopulation(); } 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 3a8589fcc..774e4f7be 100644 --- a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java @@ -95,6 +95,7 @@ public class BasicPersistentEntity> implement private final Lazy typeAlias; private final Lazy isNewStrategy; private final Lazy isImmutable; + private final Lazy requiresPropertyPopulation; /** * Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}. @@ -134,6 +135,8 @@ public class BasicPersistentEntity> implement : getFallbackIsNewStrategy()); this.isImmutable = Lazy.of(() -> isAnnotationPresent(Immutable.class)); + this.requiresPropertyPopulation = Lazy.of(() -> !isImmutable() && properties.stream() // + .anyMatch(it -> !(isConstructorArgument(it) || it.isTransient()))); } /* @@ -508,6 +511,15 @@ public class BasicPersistentEntity> implement return isImmutable.get(); } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentEntity#requiresPropertyPopulation() + */ + @Override + public boolean requiresPropertyPopulation() { + return requiresPropertyPopulation.get(); + } + /* * (non-Javadoc) * @see java.lang.Iterable#iterator() diff --git a/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java b/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java index 632b765c1..88672ea24 100755 --- a/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/BasicPersistentEntityUnitTests.java @@ -19,6 +19,8 @@ import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; import static org.mockito.Mockito.*; +import lombok.RequiredArgsConstructor; + import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,6 +29,7 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import org.hamcrest.CoreMatchers; import org.junit.Rule; @@ -44,6 +47,7 @@ import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.Immutable; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.Persistent; +import org.springframework.data.annotation.Transient; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.domain.Persistable; import org.springframework.data.mapping.Alias; @@ -355,6 +359,19 @@ public class BasicPersistentEntityUnitTests> { assertThat(createEntity(Entity.class).isImmutable()).isFalse(); } + @Test // DATACMNS-1366 + public void exposesPropertyPopulationRequired() { + + assertThat(createPopulatedPersistentEntity(PropertyPopulationRequired.class).requiresPropertyPopulation()).isTrue(); + } + + @Test // DATACMNS-1366 + public void exposesPropertyPopulationNotRequired() { + + Stream.of(PropertyPopulationNotRequired.class, PropertyPopulationNotRequiredWithTransient.class) // + .forEach(it -> assertThat(createPopulatedPersistentEntity(it).requiresPropertyPopulation()).isFalse()); + } + private BasicPersistentEntity createEntity(Class type) { return createEntity(type, null); } @@ -363,6 +380,12 @@ public class BasicPersistentEntityUnitTests> { return new BasicPersistentEntity<>(ClassTypeInformation.from(type), comparator); } + private static PersistentEntity createPopulatedPersistentEntity(Class type) { + + SampleMappingContext context = new SampleMappingContext(); + return context.getRequiredPersistentEntity(type); + } + @TypeAlias("foo") static class AliasedEntity { @@ -427,4 +450,26 @@ public class BasicPersistentEntityUnitTests> { @Immutable static class SomeValue {} + + // DATACMNS-1366 + + @RequiredArgsConstructor + static class PropertyPopulationRequired { + + private final String firstname, lastname; + private String email; + } + + @RequiredArgsConstructor + static class PropertyPopulationNotRequired { + + private final String firstname, lastname; + } + + @RequiredArgsConstructor + static class PropertyPopulationNotRequiredWithTransient { + + private final String firstname, lastname; + private @Transient String email; + } }