Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.0-3533-SNAPSHOT</version>

<name>Spring Data Core</name>
<description>Core Spring concepts underpinning every Spring Data module.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ public boolean hasNext() {
return next != null;
}

/**
* Reimplementation of {@link #getLeafProperty()} in order to
* retain the concrete type {@link SimplePropertyPath}.
*/
public SimplePropertyPath getLeafProperty() {

SimplePropertyPath result = this;

while (result.next != null) {
result = result.next;
}

return result;
}

@Override
public boolean isCollection() {
return isCollection;
Expand Down Expand Up @@ -269,18 +284,20 @@ private static boolean isQuoted(String source) {

/**
* Creates a new {@link SimplePropertyPath} as subordinary of the given {@link SimplePropertyPath}.
* <p>
* {@code base} holds one entry per part of the path, namely the part's first property. A part spelled in camel case
* stands for a chain of properties rather than a single one, so what the next part continues from is that entry's
* {@link #getLeafProperty()} leaf}, not the entry itself.
*
* @param source
* @param base
* @return
*/
private static SimplePropertyPath create(String source, Stack<SimplePropertyPath> base) {

SimplePropertyPath previous = base.peek();
SimplePropertyPath previous = base.peek().getLeafProperty();

SimplePropertyPath propertyPath = create(source, previous.typeInformation.getRequiredActualType(), base);
previous.next = propertyPath;
return propertyPath;
return create(source, previous.typeInformation.getRequiredActualType(), base);
}

/**
Expand Down Expand Up @@ -322,7 +339,7 @@ private static SimplePropertyPath create(String source, TypeInformation<?> type,
current = new SimplePropertyPath(source, type, base);

if (!base.isEmpty()) {
base.get(base.size() - 1).next = current;
base.get(base.size() - 1).getLeafProperty().next = current;
}

List<SimplePropertyPath> newBase = new ArrayList<>(base);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,54 @@ void supportsDotNotationAsWell() {
assertThat(propertyPath.getLeafProperty()).isEqualTo(PropertyPath.from("name", FooBar.class));
}

@Test // GH-3533
void continuesAfterCamelCaseSegmentAtItsLeaf() {

var propertyPath = PropertyPath.from("barUser.name", Sample.class);

assertThat(propertyPath.toDotPath()).isEqualTo("bar.user.name");
assertThat(propertyPath.getLeafProperty()).isEqualTo(PropertyPath.from("name", FooBar.class));
}

@Test // GH-3533
void continuesAfterCamelCaseSegmentAtItsLeafWithUnderscore() {

var propertyPath = PropertyPath.from("barUser_name", Sample.class);

assertThat(propertyPath.toDotPath()).isEqualTo("bar.user.name");
assertThat(propertyPath.getLeafProperty()).isEqualTo(PropertyPath.from("name", FooBar.class));
}

@Test // GH-3533
void continuesAfterCollectionCamelCaseSegmentAtItsLeaf() {
assertThat(PropertyPath.from("barUsers.name", Sample.class).toDotPath()).isEqualTo("bar.users.name");
}

@Test // GH-3533
void continuesAfterMapCamelCaseSegmentAtItsLeaf() {
assertThat(PropertyPath.from("barUserMap.name", Sample.class).toDotPath()).isEqualTo("bar.userMap.name");
}

@Test // GH-3533
void rejectsPropertyMissingOnLeafOfPrecedingCamelCaseSegment() {

// FooBar, the leaf of barUser, has no property 'user'; Bar, its owner, has one
assertThatExceptionOfType(PropertyReferenceException.class) //
.isThrownBy(() -> PropertyPath.from("barUser.user", Sample.class)) //
.withMessageContaining("No property 'user' found for type 'FooBar'");
}

@Test // GH-3533
void keepsCamelCaseSegmentIntactWhenFollowedByDotNotation() {

var propertyPath = PropertyPath.from("barUser.name", Sample.class);

List<String> segments = new ArrayList<>();
propertyPath.forEach(it -> segments.add(it.getSegment()));

assertThat(segments).containsExactly("bar", "user", "name");
}

@Test
void returnsCorrectIteratorForSingleElement() {

Expand Down
Loading