Skip to content

Commit 46fdc8a

Browse files
committed
Fix implementation of equlas/hashcode for Criteria class.
Original Pull Request: #3088 Closes: #3083 Signed-off-by: Peter-Josef Meisch <[email protected]> (cherry picked from commit 0e5af90)
1 parent 394fb7a commit 46fdc8a

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

src/main/java/org/springframework/data/elasticsearch/core/query/Criteria.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.List;
2323
import java.util.Objects;
2424
import java.util.Set;
25+
import java.util.stream.Collectors;
2526

2627
import org.springframework.dao.InvalidDataAccessApiUsageException;
2728
import org.springframework.data.elasticsearch.core.geo.GeoBox;
@@ -859,6 +860,7 @@ private List<Object> toCollection(Object... values) {
859860

860861
// endregion
861862

863+
// region equals/hashcode
862864
@Override
863865
public boolean equals(Object o) {
864866
if (this == o)
@@ -874,6 +876,8 @@ public boolean equals(Object o) {
874876
return false;
875877
if (!Objects.equals(field, criteria.field))
876878
return false;
879+
if (!criteriaChain.filter(this).equals(criteria.criteriaChain.filter(criteria)))
880+
return false;
877881
if (!queryCriteriaEntries.equals(criteria.queryCriteriaEntries))
878882
return false;
879883
if (!filterCriteriaEntries.equals(criteria.filterCriteriaEntries))
@@ -886,11 +890,16 @@ public int hashCode() {
886890
int result = field != null ? field.hashCode() : 0;
887891
result = 31 * result + (boost != +0.0f ? Float.floatToIntBits(boost) : 0);
888892
result = 31 * result + (negating ? 1 : 0);
893+
// the criteriaChain contains "this" object, so we need to filter it out
894+
// to avoid a stackoverflow here, because the hashcode implementation
895+
// uses the element's hashcodes
896+
result = 31 * result + criteriaChain.filter(this).hashCode();
889897
result = 31 * result + queryCriteriaEntries.hashCode();
890898
result = 31 * result + filterCriteriaEntries.hashCode();
891899
result = 31 * result + subCriteria.hashCode();
892900
return result;
893901
}
902+
// endregion
894903

895904
@Override
896905
public String toString() {
@@ -938,7 +947,17 @@ public Operator getOperator() {
938947
*
939948
* @since 4.1
940949
*/
941-
public static class CriteriaChain extends LinkedList<Criteria> {}
950+
public static class CriteriaChain extends LinkedList<Criteria> {
951+
/**
952+
* return a copy of this list with the given element filtered out.
953+
*
954+
* @param criteria the element to filter
955+
* @return the filtered list
956+
*/
957+
List<Criteria> filter(Criteria criteria) {
958+
return this.stream().filter(c -> c != criteria).collect(Collectors.toList());
959+
}
960+
}
942961

943962
/**
944963
* Operator to join the entries of the criteria chain

src/test/java/org/springframework/data/elasticsearch/client/elc/CriteriaQueryMappingUnitTests.java

+104
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
*/
1616
package org.springframework.data.elasticsearch.client.elc;
1717

18+
import static org.assertj.core.api.Assertions.*;
1819
import static org.skyscreamer.jsonassert.JSONAssert.*;
1920
import static org.springframework.data.elasticsearch.client.elc.JsonUtils.*;
2021

2122
import co.elastic.clients.json.JsonpMapper;
2223
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
2324

2425
import java.time.LocalDate;
26+
import java.util.ArrayList;
2527
import java.util.Collections;
2628
import java.util.Date;
2729
import java.util.List;
@@ -445,6 +447,108 @@ void shouldMapNamesInSourceStoredFields() {
445447
softly.assertAll();
446448
}
447449

450+
// the following test failed because of a wrong implementation in Criteria
451+
// equals and hscode methods.
452+
@Test // #3083
453+
@DisplayName("should map correct subcriteria")
454+
void shouldMapCorrectSubcriteria() throws JSONException {
455+
Criteria criteria = new Criteria("first").is("hello");
456+
457+
List<Criteria> criterias = new ArrayList<>();
458+
criterias.add(new Criteria().or("second").exists());
459+
460+
List<Criteria> subCriterias = new ArrayList<>();
461+
subCriterias.add(new Criteria("third").exists()
462+
.and(new Criteria("fourth").is("ciao")));
463+
subCriterias.add(new Criteria("third").exists()
464+
.and(new Criteria("fourth").is("hi")));
465+
466+
Criteria result = Criteria.or();
467+
468+
for (Criteria c : criterias) {
469+
result = result.or(c);
470+
}
471+
472+
for (Criteria c : subCriterias) {
473+
result = result.subCriteria(c);
474+
}
475+
criteria = criteria.subCriteria(result);
476+
CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
477+
478+
String expected = """
479+
{
480+
"bool": {
481+
"must": [
482+
{
483+
"query_string": {
484+
"default_operator": "and",
485+
"fields": [
486+
"first"
487+
],
488+
"query": "hello"
489+
}
490+
},
491+
{
492+
"bool": {
493+
"should": [
494+
{
495+
"exists": {
496+
"field": "second"
497+
}
498+
},
499+
{
500+
"bool": {
501+
"must": [
502+
{
503+
"exists": {
504+
"field": "third"
505+
}
506+
},
507+
{
508+
"query_string": {
509+
"default_operator": "and",
510+
"fields": [
511+
"fourth"
512+
],
513+
"query": "ciao"
514+
}
515+
}
516+
]
517+
}
518+
},
519+
{
520+
"bool": {
521+
"must": [
522+
{
523+
"exists": {
524+
"field": "third"
525+
}
526+
},
527+
{
528+
"query_string": {
529+
"default_operator": "and",
530+
"fields": [
531+
"fourth"
532+
],
533+
"query": "hi"
534+
}
535+
}
536+
]
537+
}
538+
}
539+
]
540+
}
541+
}
542+
]
543+
}
544+
}
545+
""";
546+
547+
mappingElasticsearchConverter.updateQuery(criteriaQuery, Person.class);
548+
var queryString = queryToJson(CriteriaQueryProcessor.createQuery(criteriaQuery.getCriteria()), mapper);
549+
550+
assertEquals(expected, queryString, false);
551+
}
448552
// endregion
449553
// region helper functions
450554

0 commit comments

Comments
 (0)