diff --git a/pom.xml b/pom.xml index 2ace266bf9..e3ad2b9562 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-commons - 4.2.0-SNAPSHOT + 4.2.0-GH-3515-SNAPSHOT Spring Data Core Core Spring concepts underpinning every Spring Data module. diff --git a/src/main/java/org/springframework/data/mapping/context/MappingContext.java b/src/main/java/org/springframework/data/mapping/context/MappingContext.java index 1fe20a5677..eedf1dbb6f 100644 --- a/src/main/java/org/springframework/data/mapping/context/MappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/MappingContext.java @@ -134,14 +134,13 @@ default E getRequiredPersistentEntity(TypeInformation type) throws MappingExc E getPersistentEntity(P persistentProperty); /** - * Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}. + * Returns the {@link PersistentEntity} mapped by the given {@link PersistentProperty}. Will throw + * {@link MappingException} for types that are considered simple ones. * * @param persistentProperty must not be {@literal null}. - * @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty} or {@literal null} if no - * {@link PersistentEntity} exists for it or the {@link PersistentProperty} does not refer to an entity (the - * type of the property is considered simple see - * {@link org.springframework.data.mapping.model.SimpleTypeHolder#isSimpleType(Class)}). + * @return the {@link PersistentEntity} mapped by the given {@link PersistentProperty}. * @throws MappingException when no {@link PersistentEntity} can be found for given {@link PersistentProperty}. + * @see #getPersistentEntity(PersistentProperty) */ default E getRequiredPersistentEntity(P persistentProperty) throws MappingException { diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java index b377ad524b..a639782e05 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java @@ -15,8 +15,16 @@ */ package org.springframework.data.mapping.context; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -49,8 +57,6 @@ */ class PersistentPropertyPathFactory, P extends PersistentProperty

> { - private static final Predicate>> IS_ENTITY = PersistentProperty::isEntity; - private final ConcurrentLruCache propertyPaths = new ConcurrentLruCache<>(512, it -> createPersistentPropertyPath(it.path(), it.type())); private final MappingContext context; @@ -228,7 +234,18 @@ private Collection> from(TypeInformation type, return Collections.emptyList(); } - return from(context.getRequiredPersistentEntity(actualType), filter, traversalGuard, basePath); + E entity; + if (type.isCollectionLike() || type.isMap()) { + entity = context.getPersistentEntity(actualType); + } else { + entity = context.getRequiredPersistentEntity(actualType); + } + + if (entity == null) { + return Collections.emptyList(); + } + + return from(entity, filter, traversalGuard, basePath); } private Collection> from(E entity, Predicate filter, Predicate

traversalGuard, @@ -251,9 +268,11 @@ private Collection> from(E entity, Predicate true); + + var factory = new MappingAuditableBeanWrapperFactory(PersistentEntities.of(context)); + + assertThat(factory.getBeanWrapperFor(new WithNestedMap())).isNotNull(); + } + @Test // DATACMNS-365 void discoversAuditingPropertyOnField() { @@ -406,4 +418,12 @@ static class WithEmbedded { Collection embeddeds; Map embeddedMap; } + + static class Cell { + Object value; + } + + static class WithNestedMap { + Map> values; + } } diff --git a/src/test/java/org/springframework/data/mapping/context/PersistentPropertyPathFactoryUnitTests.java b/src/test/java/org/springframework/data/mapping/context/PersistentPropertyPathFactoryUnitTests.java index eb56b73efe..24dc829389 100644 --- a/src/test/java/org/springframework/data/mapping/context/PersistentPropertyPathFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/context/PersistentPropertyPathFactoryUnitTests.java @@ -41,6 +41,7 @@ * * @author Oliver Gierke * @author Christoph Strobl + * @author Mark Paluch * @soundtrack Cypress Hill - Illusions (Q-Tip Remix, Unreleased & Revamped) */ class PersistentPropertyPathFactoryUnitTests { @@ -176,6 +177,22 @@ void returnsShortestPathFirst() { .hasValueSatisfying(it -> assertThat(it.toDotPath()).isEqualTo("third.lastname")); } + @Test // GH-3515 + void returnsPathsForMapWithEntityKeyAndSimpleValueType() { + + var paths = factory.from(WithEntityKeyMap.class, it -> true); + + assertThat(paths).extracting(PersistentPropertyPath::toDotPath).containsExactly("map"); + } + + @Test // GH-3515 + void returnsPathsForRawTypeComplexBound() { + + var paths = factory.from(BoundedGeneric.class, it -> true); + + assertThat(paths).extracting(PersistentPropertyPath::toDotPath).containsExactly("map"); + } + static class PersonSample { List persons; } @@ -222,4 +239,13 @@ static class Second { static class Third { String lastname; } + + static class WithEntityKeyMap { + Map map; + } + + static class BoundedGeneric { + Map map; + } + }