diff --git a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index 7aa2b25fb..d8a90203c 100644 --- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -18,6 +18,7 @@ package org.springframework.data.mapping.context; import lombok.AccessLevel; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.Value; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; @@ -28,6 +29,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -55,6 +57,7 @@ import org.springframework.data.util.Pair; import org.springframework.data.util.Streamable; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; +import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.FieldCallback; import org.springframework.util.ReflectionUtils.FieldFilter; @@ -83,6 +86,7 @@ public abstract class AbstractMappingContext NONE = Optional.empty(); private final Map, Optional> persistentEntities = new HashMap<>(); + private final Map> propertyPaths = new ConcurrentReferenceHashMap<>(); private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory = new ClassGeneratingPropertyAccessorFactory(); private ApplicationEventPublisher applicationEventPublisher; @@ -268,18 +272,21 @@ public abstract class AbstractMappingContext getPersistentPropertyPath(String propertyPath, TypeInformation type) { - return getPersistentPropertyPath(Arrays.asList(propertyPath.split("\\.")), type); + + return propertyPaths.computeIfAbsent(TypeAndProperties.of(type, propertyPath), + it -> createPersistentPropertyPath(it.getPath(), it.getType())); } /** * Creates a {@link PersistentPropertyPath} for the given parts and {@link TypeInformation}. * - * @param parts must not be {@literal null} or empty. + * @param propertyPath must not be {@literal null}. * @param type must not be {@literal null}. * @return */ - private PersistentPropertyPath

getPersistentPropertyPath(Collection parts, TypeInformation type) { + private PersistentPropertyPath

createPersistentPropertyPath(String propertyPath, TypeInformation type) { + List parts = Arrays.asList(propertyPath.split("\\.")); DefaultPersistentPropertyPath

path = DefaultPersistentPropertyPath.empty(); Iterator iterator = parts.iterator(); E current = getRequiredPersistentEntity(type); @@ -545,6 +552,13 @@ public abstract class AbstractMappingContext type; + String path; + } + /** * Filter rejecting static fields as well as artificially introduced ones. See * {@link PersistentPropertyFilter#UNMAPPED_PROPERTIES} for details. diff --git a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java index 3bfc101b7..b89c762ac 100755 --- a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java @@ -31,10 +31,10 @@ import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.data.annotation.Id; +import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.model.BasicPersistentEntity; -import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; @@ -155,7 +155,7 @@ public class AbstractMappingContextUnitTests { assertThat(entity.getPersistentProperty("persons")) .satisfies(it -> assertThat(mappingContext.getPersistentEntity(it)) - .satisfies(inner -> assertThat(((PersistentEntity)inner).getType()).isEqualTo(Person.class))); + .satisfies(inner -> assertThat(((PersistentEntity) inner).getType()).isEqualTo(Person.class))); } @Test // DATACMNS-380 @@ -226,6 +226,13 @@ public class AbstractMappingContextUnitTests { .matches(e -> context.getPersistentPropertyPath(e) != null); } + @Test // DATACMNS-1116 + public void cachesPersistentPropertyPaths() { + + assertThat(context.getPersistentPropertyPath("persons.name", Sample.class)) // + .isSameAs(context.getPersistentPropertyPath("persons.name", Sample.class)); + } + private static void assertHasEntityFor(Class type, SampleMappingContext context, boolean expected) { boolean found = false;