diff --git a/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java b/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java index 5e76469077..cf0d2323ca 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PersistentPropertyPath.java @@ -29,8 +29,6 @@ public interface PersistentPropertyPath

> extends /** * Returns the dot based path notation using {@link PersistentProperty#getName()}. - * - * @return */ @Nullable String toDotPath(); @@ -40,7 +38,6 @@ public interface PersistentPropertyPath

> extends * {@link PersistentProperty}s to path segments. * * @param converter must not be {@literal null}. - * @return */ @Nullable String toDotPath(Converter converter); @@ -49,7 +46,6 @@ public interface PersistentPropertyPath

> extends * Returns a {@link String} path with the given delimiter based on the {@link PersistentProperty#getName()}. * * @param delimiter must not be {@literal null}. - * @return */ @Nullable String toPath(String delimiter); @@ -60,7 +56,6 @@ public interface PersistentPropertyPath

> extends * * @param delimiter must not be {@literal null}. * @param converter must not be {@literal null}. - * @return */ @Nullable String toPath(String delimiter, Converter converter); @@ -70,7 +65,6 @@ public interface PersistentPropertyPath

> extends * {@link PersistentProperty} for {@code bar}. For a simple {@code foo} it returns {@link PersistentProperty} for * {@code foo}. * - * @return */ @Nullable P getLeafProperty(); @@ -90,28 +84,24 @@ default P getRequiredLeafProperty() { * Returns the first property in the {@link PersistentPropertyPath}. So for {@code foo.bar} it will return the * {@link PersistentProperty} for {@code foo}. For a simple {@code foo} it returns {@link PersistentProperty} for * {@code foo}. - * - * @return */ @Nullable P getBaseProperty(); /** * Returns whether the given {@link PersistentPropertyPath} is a base path of the current one. This means that the - * current {@link PersistentPropertyPath} is basically an extension of the given one. + * given {@link PersistentPropertyPath} is basically an extension of this {@link PersistentPropertyPath}. * * @param path must not be {@literal null}. - * @return */ boolean isBasePathOf(PersistentPropertyPath

path); /** * Returns the sub-path of the current one as if it was based on the given base path. So for a current path * {@code foo.bar} and a given base {@code foo} it would return {@code bar}. If the given path is not a base of the - * the current one the current {@link PersistentPropertyPath} will be returned as is. + * current one the current {@link PersistentPropertyPath} will be returned as is. * * @param base must not be {@literal null}. - * @return */ PersistentPropertyPath

getExtensionForBaseOf(PersistentPropertyPath

base); @@ -119,15 +109,11 @@ default P getRequiredLeafProperty() { * Returns the parent path of the current {@link PersistentPropertyPath}, i.e. the path without the leaf property. * This happens up to the base property. So for a direct property reference calling this method will result in * returning the property. - * - * @return */ PersistentPropertyPath

getParentPath(); /** * Returns the length of the {@link PersistentPropertyPath}. - * - * @return */ int getLength(); } diff --git a/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java b/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java index 0b1f2927db..3d9a468bf4 100644 --- a/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPath.java @@ -38,7 +38,7 @@ */ class DefaultPersistentPropertyPath

> implements PersistentPropertyPath

{ - private static final Converter, String> DEFAULT_CONVERTER = (source) -> source.getName(); + private static final Converter, String> DEFAULT_CONVERTER = PersistentProperty::getName; private static final String DEFAULT_DELIMITER = "."; private final List

properties; @@ -131,25 +131,43 @@ public P getBaseProperty() { } public boolean isBasePathOf(PersistentPropertyPath

path) { + return this.equals(getCommonBaseWith(path)); + } - Assert.notNull(path, "PersistentPropertyPath must not be null"); + /** + * Return the common base path that this {@link PersistentPropertyPath} has with passed {@link PersistentPropertyPath} + * + * That is, for example, if this {@link PersistentPropertyPath} equals to one.two.three, and passed {@link PersistentPropertyPath} + * is equals to one.two.four, that the return will be the {@link PersistentPropertyPath} containing one.two properties + */ + public PersistentPropertyPath

getCommonBaseWith(PersistentPropertyPath

anotherPath) { + + Assert.notNull(anotherPath, "PersistentPropertyPath must not be null"); + + if (anotherPath.isEmpty()) { + return DefaultPersistentPropertyPath.empty(); + } - Iterator

iterator = path.iterator(); + List

commonPart = new ArrayList<>(); - for (P property : this) { + Iterator

iterator = anotherPath.iterator(); + + for (P property: this) { if (!iterator.hasNext()) { - return false; + break; } - P reference = iterator.next(); + P next = iterator.next(); - if (!property.equals(reference)) { - return false; + if (property.equals(next)) { + commonPart.add(property); + } else { + break; } } - return true; + return new DefaultPersistentPropertyPath<>(commonPart); } public PersistentPropertyPath

getExtensionForBaseOf(PersistentPropertyPath

base) { @@ -158,18 +176,7 @@ public PersistentPropertyPath

getExtensionForBaseOf(PersistentPropertyPath

return this; } - List

result = new ArrayList<>(); - Iterator

iterator = iterator(); - - for (int i = 0; i < base.getLength(); i++) { - iterator.next(); - } - - while (iterator.hasNext()) { - result.add(iterator.next()); - } - - return new DefaultPersistentPropertyPath<>(result); + return new DefaultPersistentPropertyPath<>(properties.subList(base.getLength(), properties.size())); } public PersistentPropertyPath

getParentPath() { diff --git a/src/test/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPathUnitTests.java b/src/test/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPathUnitTests.java index 4da5788073..0f272f534a 100755 --- a/src/test/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPathUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/context/DefaultPersistentPropertyPathUnitTests.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,7 +41,7 @@ @ExtendWith(MockitoExtension.class) class DefaultPersistentPropertyPathUnitTests

> { - @Mock P first, second; + @Mock P first, second, third; @Mock Converter converter; @@ -58,6 +59,65 @@ void rejectsNullProperties() { assertThatIllegalArgumentException().isThrownBy(() -> new DefaultPersistentPropertyPath<>(null)); } + @Test + void getCommonBaseTestEmpty() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + assertThat(propertyPath.getCommonBaseWith(DefaultPersistentPropertyPath.empty())).isEmpty(); + } + + @Test + void getCommonBaseTestNoCommonBase() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first)); + + assertThat(propertyPath.getCommonBaseWith(new DefaultPersistentPropertyPath<>(List.of(second)))).isEmpty(); + } + + @Test + void getCommonBaseTestCommonBasePresentInPassed() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first)); + + assertThat(propertyPath.getCommonBaseWith(new DefaultPersistentPropertyPath<>(List.of(first, second)))).isEqualTo(propertyPath); + } + + @Test + void getCommonBaseTestCommonBasePresentInThis() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + DefaultPersistentPropertyPath

anotherPath = new DefaultPersistentPropertyPath<>(List.of(first)); + + assertThat(propertyPath.getCommonBaseWith(anotherPath)).isEqualTo(anotherPath); + } + + @Test + void getCommonBaseTestTheSamePath() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + DefaultPersistentPropertyPath

anotherPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + assertThat(propertyPath.getCommonBaseWith(anotherPath)).isEqualTo(anotherPath); + } + + @Test + void getCommonBaseTestHasSamePropertiesInDifferentOrder() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + DefaultPersistentPropertyPath

anotherPath = new DefaultPersistentPropertyPath<>(List.of(second, first)); + + assertThat(propertyPath.getCommonBaseWith(anotherPath)).isEqualTo(DefaultPersistentPropertyPath.empty()); + } + + + @Test + void getCommonBaseTestHasSamePropertiesButNotInBase() { + DefaultPersistentPropertyPath

propertyPath = new DefaultPersistentPropertyPath<>(List.of(first, second)); + + DefaultPersistentPropertyPath

anotherPath = new DefaultPersistentPropertyPath<>(List.of(third, second)); + + assertThat(propertyPath.getCommonBaseWith(anotherPath)).isEqualTo(DefaultPersistentPropertyPath.empty()); + } + + @Test void usesPropertyNameForSimpleDotPath() {