This fixes immutability of clauseSets (broken by #13950) (#14074)

This commit is contained in:
Uwe Schindler 2024-12-17 14:52:42 +01:00
parent 6a0531b0f4
commit 884954006d
2 changed files with 37 additions and 2 deletions

View File

@ -124,7 +124,8 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
private final int minimumNumberShouldMatch;
private final List<BooleanClause> clauses; // used for toString() and getClauses()
private final Map<Occur, Collection<Query>> clauseSets; // used for equals/hashcode
// WARNING: Do not let clauseSets escape from this class as it breaks immutability:
private final Map<Occur, Collection<Query>> clauseSets; // used for equals/hashCode
private BooleanQuery(int minimumNumberShouldMatch, BooleanClause[] clauses) {
this.minimumNumberShouldMatch = minimumNumberShouldMatch;
@ -153,7 +154,9 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
/** Return the collection of queries for the given {@link Occur}. */
public Collection<Query> getClauses(Occur occur) {
return clauseSets.get(occur);
// turn this immutable here, because we need to preserve the correct collection types for
// equals/hashCode!
return Collections.unmodifiableCollection(clauseSets.get(occur));
}
/**

View File

@ -1383,4 +1383,36 @@ public class TestBooleanQuery extends LuceneTestCase {
}
});
}
public void testClauseSetsImmutability() throws Exception {
Term a = new Term("f", "a");
Term b = new Term("f", "b");
Term c = new Term("f", "c");
Term d = new Term("f", "d");
BooleanQuery.Builder bqBuilder = new BooleanQuery.Builder();
bqBuilder.add(new TermQuery(a), Occur.SHOULD);
bqBuilder.add(new TermQuery(a), Occur.SHOULD);
bqBuilder.add(new TermQuery(b), Occur.MUST);
bqBuilder.add(new TermQuery(b), Occur.MUST);
bqBuilder.add(new TermQuery(c), Occur.FILTER);
bqBuilder.add(new TermQuery(c), Occur.FILTER);
bqBuilder.add(new TermQuery(d), Occur.MUST_NOT);
bqBuilder.add(new TermQuery(d), Occur.MUST_NOT);
BooleanQuery bq = bqBuilder.build();
// should and must are not dedupliacated
assertEquals(2, bq.getClauses(Occur.SHOULD).size());
assertEquals(2, bq.getClauses(Occur.MUST).size());
// filter and must not are deduplicated
assertEquals(1, bq.getClauses(Occur.FILTER).size());
assertEquals(1, bq.getClauses(Occur.MUST_NOT).size());
// check immutability
for (var occur : Occur.values()) {
assertThrows(
UnsupportedOperationException.class,
() -> bq.getClauses(occur).add(new MatchNoDocsQuery()));
}
assertThrows(
UnsupportedOperationException.class,
() -> bq.clauses().add(new BooleanClause(new MatchNoDocsQuery(), Occur.SHOULD)));
}
}