Skip to content

Commit 394fb7a

Browse files
committed
Fix cutting of unknown properties in property paths for search.
Original Pull Request #3082 Closes #3081 Signed-off-by: Peter-Josef Meisch <[email protected]> (cherry picked from commit 1ae6301)
1 parent c23da6e commit 394fb7a

File tree

2 files changed

+101
-57
lines changed

2 files changed

+101
-57
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java

+59-57
Original file line numberDiff line numberDiff line change
@@ -1358,53 +1358,21 @@ private void updatePropertiesInCriteria(Criteria criteria, ElasticsearchPersiste
13581358
return;
13591359
}
13601360

1361-
String[] fieldNames = field.getName().split("\\.");
1362-
1363-
ElasticsearchPersistentEntity<?> currentEntity = persistentEntity;
1364-
ElasticsearchPersistentProperty persistentProperty = null;
1365-
int propertyCount = 0;
1366-
boolean isNested = false;
1367-
1368-
for (int i = 0; i < fieldNames.length; i++) {
1369-
persistentProperty = currentEntity.getPersistentProperty(fieldNames[i]);
1370-
1371-
if (persistentProperty != null) {
1372-
propertyCount++;
1373-
fieldNames[i] = persistentProperty.getFieldName();
1374-
1375-
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = persistentProperty
1376-
.findAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
1377-
1378-
if (fieldAnnotation != null && fieldAnnotation.type() == FieldType.Nested) {
1379-
isNested = true;
1380-
}
1381-
1382-
try {
1383-
currentEntity = mappingContext.getPersistentEntity(persistentProperty.getActualType());
1384-
} catch (Exception e) {
1385-
// using system types like UUIDs will lead to java.lang.reflect.InaccessibleObjectException in JDK 16
1386-
// so if we cannot get an entity here, bail out.
1387-
currentEntity = null;
1388-
}
1389-
}
1390-
1391-
if (currentEntity == null) {
1392-
break;
1393-
}
1394-
}
1361+
var propertyNamesUpdate = updatePropertyNames(persistentEntity, field.getName());
13951362

1363+
var fieldNames = propertyNamesUpdate.names();
13961364
field.setName(String.join(".", fieldNames));
13971365

1398-
if (propertyCount > 1 && isNested) {
1366+
if (propertyNamesUpdate.propertyCount() > 1 && propertyNamesUpdate.nestedProperty()) {
13991367
List<String> propertyNames = Arrays.asList(fieldNames);
1400-
field.setPath(String.join(".", propertyNames.subList(0, propertyCount - 1)));
1368+
field.setPath(String.join(".", propertyNames.subList(0, propertyNamesUpdate.propertyCount - 1)));
14011369
}
14021370

1403-
if (persistentProperty != null) {
1371+
if (propertyNamesUpdate.persistentProperty != null) {
14041372

1405-
if (persistentProperty.hasPropertyValueConverter()) {
1373+
if (propertyNamesUpdate.persistentProperty.hasPropertyValueConverter()) {
14061374
PropertyValueConverter propertyValueConverter = Objects
1407-
.requireNonNull(persistentProperty.getPropertyValueConverter());
1375+
.requireNonNull(propertyNamesUpdate.persistentProperty.getPropertyValueConverter());
14081376
criteria.getQueryCriteriaEntries().forEach(criteriaEntry -> {
14091377

14101378
if (criteriaEntry.getKey().hasValue()) {
@@ -1423,7 +1391,7 @@ private void updatePropertiesInCriteria(Criteria criteria, ElasticsearchPersiste
14231391
});
14241392
}
14251393

1426-
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = persistentProperty
1394+
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = propertyNamesUpdate.persistentProperty
14271395
.findAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
14281396

14291397
if (fieldAnnotation != null) {
@@ -1432,36 +1400,70 @@ private void updatePropertiesInCriteria(Criteria criteria, ElasticsearchPersiste
14321400
}
14331401
}
14341402

1403+
static record PropertyNamesUpdate(
1404+
String[] names,
1405+
Boolean nestedProperty,
1406+
Integer propertyCount,
1407+
ElasticsearchPersistentProperty persistentProperty) {
1408+
}
1409+
14351410
@Override
14361411
public String updateFieldNames(String propertyPath, ElasticsearchPersistentEntity<?> persistentEntity) {
14371412

14381413
Assert.notNull(propertyPath, "propertyPath must not be null");
14391414
Assert.notNull(persistentEntity, "persistentEntity must not be null");
14401415

1441-
var properties = propertyPath.split("\\.", 2);
1416+
var propertyNamesUpdate = updatePropertyNames(persistentEntity, propertyPath);
1417+
return String.join(".", propertyNamesUpdate.names());
1418+
}
14421419

1443-
if (properties.length > 0) {
1444-
var propertyName = properties[0];
1445-
var fieldName = propertyToFieldName(persistentEntity, propertyName);
1420+
/**
1421+
* Parse a propertyPath and replace the path values with the field names from a persistentEntity. path entries not
1422+
* found in the entity are kept as they are.
1423+
*
1424+
* @return the eventually modified names, a flag if a nested entity was encountered the number of processed
1425+
* propertiesand the last processed PersistentProperty.
1426+
*/
1427+
PropertyNamesUpdate updatePropertyNames(ElasticsearchPersistentEntity<?> persistentEntity, String propertyPath) {
14461428

1447-
if (properties.length > 1) {
1448-
var persistentProperty = persistentEntity.getPersistentProperty(propertyName);
1429+
String[] propertyNames = propertyPath.split("\\.");
1430+
String[] fieldNames = Arrays.copyOf(propertyNames, propertyNames.length);
14491431

1450-
if (persistentProperty != null) {
1451-
ElasticsearchPersistentEntity<?> nestedPersistentEntity = mappingContext
1452-
.getPersistentEntity(persistentProperty);
1453-
if (nestedPersistentEntity != null) {
1454-
return fieldName + '.' + updateFieldNames(properties[1], nestedPersistentEntity);
1455-
} else {
1456-
return fieldName;
1457-
}
1432+
ElasticsearchPersistentEntity<?> currentEntity = persistentEntity;
1433+
ElasticsearchPersistentProperty persistentProperty = null;
1434+
1435+
int propertyCount = 0;
1436+
boolean isNested = false;
1437+
1438+
for (int i = 0; i < propertyNames.length; i++) {
1439+
persistentProperty = currentEntity.getPersistentProperty(propertyNames[i]);
1440+
1441+
if (persistentProperty != null) {
1442+
propertyCount++;
1443+
fieldNames[i] = persistentProperty.getFieldName();
1444+
1445+
org.springframework.data.elasticsearch.annotations.Field fieldAnnotation = persistentProperty
1446+
.findAnnotation(org.springframework.data.elasticsearch.annotations.Field.class);
1447+
1448+
if (fieldAnnotation != null && fieldAnnotation.type() == FieldType.Nested) {
1449+
isNested = true;
1450+
}
1451+
1452+
try {
1453+
currentEntity = mappingContext.getPersistentEntity(persistentProperty.getActualType());
1454+
} catch (Exception e) {
1455+
// using system types like UUIDs will lead to java.lang.reflect.InaccessibleObjectException in JDK 16
1456+
// so if we cannot get an entity here, bail out.
1457+
currentEntity = null;
14581458
}
14591459
}
1460-
return fieldName;
1461-
} else {
1462-
return propertyPath;
1460+
1461+
if (currentEntity == null) {
1462+
break;
1463+
}
14631464
}
14641465

1466+
return new PropertyNamesUpdate(fieldNames, isNested, propertyCount, persistentProperty);
14651467
}
14661468
// endregion
14671469

Diff for: src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java

+42
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.query;
1717

18+
import static org.assertj.core.api.Assertions.*;
1819
import static org.skyscreamer.jsonassert.JSONAssert.*;
1920

2021
import java.lang.reflect.Method;
@@ -27,6 +28,7 @@
2728
import org.junit.jupiter.api.Test;
2829
import org.springframework.beans.factory.annotation.Autowired;
2930
import org.springframework.data.annotation.Id;
31+
import org.springframework.data.domain.Sort;
3032
import org.springframework.data.elasticsearch.annotations.Field;
3133
import org.springframework.data.elasticsearch.annotations.FieldType;
3234
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
@@ -679,6 +681,45 @@ void shouldBuildSortObjectWithCorrectFieldNames() throws NoSuchMethodException,
679681
assertEquals(expected, query, false);
680682
}
681683

684+
@Test // #3081
685+
@DisplayName("should build sort object with unknown field names")
686+
void shouldBuildSortObjectWithUnknownFieldNames() throws NoSuchMethodException, JSONException {
687+
688+
String methodName = "findByName";
689+
Class<?>[] parameterClasses = new Class[] { String.class, Sort.class };
690+
Object[] parameters = new Object[] { BOOK_TITLE, Sort.by("sortAuthor.sortName.raw") };
691+
692+
String query = getQueryString(methodName, parameterClasses, parameters);
693+
694+
String expected = """
695+
696+
{
697+
"query": {
698+
"bool": {
699+
"must": [
700+
{
701+
"query_string": {
702+
"query": "Title",
703+
"fields": [
704+
"name"
705+
]
706+
}
707+
}
708+
]
709+
}
710+
},
711+
"sort": [
712+
{
713+
"sort_author.sort_name.raw": {
714+
"order": "asc"
715+
}
716+
}
717+
]
718+
}""";
719+
720+
assertEquals(expected, query, false);
721+
}
722+
682723
private String getQueryString(String methodName, Class<?>[] parameterClasses, Object[] parameters)
683724
throws NoSuchMethodException {
684725

@@ -768,6 +809,7 @@ private interface SampleRepository extends ElasticsearchRepository<Book, String>
768809

769810
List<Book> findByNameOrderBySortAuthor_SortName(String name);
770811

812+
List<Book> findByName(String name, Sort sort);
771813
}
772814

773815
public static class Book {

0 commit comments

Comments
 (0)