Skip to content

Commit 8849540

Browse files
committedDec 17, 2024
This fixes immutability of clauseSets (broken by #13950) (#14074)
1 parent 6a0531b commit 8849540

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed
 

‎lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ public BooleanQuery build() {
124124

125125
private final int minimumNumberShouldMatch;
126126
private final List<BooleanClause> clauses; // used for toString() and getClauses()
127-
private final Map<Occur, Collection<Query>> clauseSets; // used for equals/hashcode
127+
// WARNING: Do not let clauseSets escape from this class as it breaks immutability:
128+
private final Map<Occur, Collection<Query>> clauseSets; // used for equals/hashCode
128129

129130
private BooleanQuery(int minimumNumberShouldMatch, BooleanClause[] clauses) {
130131
this.minimumNumberShouldMatch = minimumNumberShouldMatch;
@@ -153,7 +154,9 @@ public List<BooleanClause> clauses() {
153154

154155
/** Return the collection of queries for the given {@link Occur}. */
155156
public Collection<Query> getClauses(Occur occur) {
156-
return clauseSets.get(occur);
157+
// turn this immutable here, because we need to preserve the correct collection types for
158+
// equals/hashCode!
159+
return Collections.unmodifiableCollection(clauseSets.get(occur));
157160
}
158161

159162
/**

‎lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java

+32
Original file line numberDiff line numberDiff line change
@@ -1383,4 +1383,36 @@ public void consumeTerms(Query query, Term... terms) {
13831383
}
13841384
});
13851385
}
1386+
1387+
public void testClauseSetsImmutability() throws Exception {
1388+
Term a = new Term("f", "a");
1389+
Term b = new Term("f", "b");
1390+
Term c = new Term("f", "c");
1391+
Term d = new Term("f", "d");
1392+
BooleanQuery.Builder bqBuilder = new BooleanQuery.Builder();
1393+
bqBuilder.add(new TermQuery(a), Occur.SHOULD);
1394+
bqBuilder.add(new TermQuery(a), Occur.SHOULD);
1395+
bqBuilder.add(new TermQuery(b), Occur.MUST);
1396+
bqBuilder.add(new TermQuery(b), Occur.MUST);
1397+
bqBuilder.add(new TermQuery(c), Occur.FILTER);
1398+
bqBuilder.add(new TermQuery(c), Occur.FILTER);
1399+
bqBuilder.add(new TermQuery(d), Occur.MUST_NOT);
1400+
bqBuilder.add(new TermQuery(d), Occur.MUST_NOT);
1401+
BooleanQuery bq = bqBuilder.build();
1402+
// should and must are not dedupliacated
1403+
assertEquals(2, bq.getClauses(Occur.SHOULD).size());
1404+
assertEquals(2, bq.getClauses(Occur.MUST).size());
1405+
// filter and must not are deduplicated
1406+
assertEquals(1, bq.getClauses(Occur.FILTER).size());
1407+
assertEquals(1, bq.getClauses(Occur.MUST_NOT).size());
1408+
// check immutability
1409+
for (var occur : Occur.values()) {
1410+
assertThrows(
1411+
UnsupportedOperationException.class,
1412+
() -> bq.getClauses(occur).add(new MatchNoDocsQuery()));
1413+
}
1414+
assertThrows(
1415+
UnsupportedOperationException.class,
1416+
() -> bq.clauses().add(new BooleanClause(new MatchNoDocsQuery(), Occur.SHOULD)));
1417+
}
13861418
}

0 commit comments

Comments
 (0)
Please sign in to comment.