Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 948421) +++ CHANGES.txt (working copy) @@ -406,6 +406,9 @@ lock (previously we only released on IOException). (Tamas Cservenak via Mike McCandless) +* LUCENE-2478: Fix CachingWrapperFilter to not throw NPE when + Filter.getDocIdSet() returns null. (Uwe Schindler, Daniel Noll) + New features * LUCENE-2128: Parallelized fetching document frequencies during weight Index: src/java/org/apache/lucene/search/CachingWrapperFilter.java =================================================================== --- src/java/org/apache/lucene/search/CachingWrapperFilter.java (revision 948421) +++ src/java/org/apache/lucene/search/CachingWrapperFilter.java (working copy) @@ -53,7 +53,10 @@ * an {@link OpenBitSetDISI}. */ protected DocIdSet docIdSetToCache(DocIdSet docIdSet, IndexReader reader) throws IOException { - if (docIdSet.isCacheable()) { + if (docIdSet == null) { + // this is better than returning null, as the nonnull result can be cached + return DocIdSet.EMPTY_DOCIDSET; + } else if (docIdSet.isCacheable()) { return docIdSet; } else { final DocIdSetIterator it = docIdSet.iterator(); Index: src/test/org/apache/lucene/search/TestCachingWrapperFilter.java =================================================================== --- src/test/org/apache/lucene/search/TestCachingWrapperFilter.java (revision 948421) +++ src/test/org/apache/lucene/search/TestCachingWrapperFilter.java (working copy) @@ -57,6 +57,55 @@ reader.close(); } + public void testNullDocIdSet() throws Exception { + Directory dir = new RAMDirectory(); + IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig( + TEST_VERSION_CURRENT, new MockAnalyzer())); + writer.close(); + + IndexReader reader = IndexReader.open(dir, true); + + final Filter filter = new Filter() { + @Override + public DocIdSet getDocIdSet(IndexReader reader) { + return null; + } + }; + CachingWrapperFilter cacher = new CachingWrapperFilter(filter); + + // the caching filter should return the empty set constant + assertSame(DocIdSet.EMPTY_DOCIDSET, cacher.getDocIdSet(reader)); + + reader.close(); + } + + public void testNullDocIdSetIterator() throws Exception { + Directory dir = new RAMDirectory(); + IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig( + TEST_VERSION_CURRENT, new MockAnalyzer())); + writer.close(); + + IndexReader reader = IndexReader.open(dir, true); + + final Filter filter = new Filter() { + @Override + public DocIdSet getDocIdSet(IndexReader reader) { + return new DocIdSet() { + @Override + public DocIdSetIterator iterator() { + return null; + } + }; + } + }; + CachingWrapperFilter cacher = new CachingWrapperFilter(filter); + + // the caching filter should return the empty set constant + assertSame(DocIdSet.EMPTY_DOCIDSET, cacher.getDocIdSet(reader)); + + reader.close(); + } + private static void assertDocIdSetCacheable(IndexReader reader, Filter filter, boolean shouldCacheable) throws IOException { final CachingWrapperFilter cacher = new CachingWrapperFilter(filter); final DocIdSet originalSet = filter.getDocIdSet(reader);