Index: lucene/codecs/src/java/org/apache/lucene/codecs/appending/AppendingCodec.java =================================================================== --- lucene/codecs/src/java/org/apache/lucene/codecs/appending/AppendingCodec.java (revision 1391096) +++ lucene/codecs/src/java/org/apache/lucene/codecs/appending/AppendingCodec.java (working copy) @@ -17,7 +17,6 @@ * limitations under the License. */ -import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.FilterCodec; import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.lucene40.Lucene40Codec; @@ -32,17 +31,12 @@ public final class AppendingCodec extends FilterCodec { public AppendingCodec() { - super("Appending"); + super("Appending", new Lucene40Codec()); } private final PostingsFormat postings = new AppendingPostingsFormat(); @Override - protected Codec delegate() { - return Codec.forName("Lucene40"); - } - - @Override public PostingsFormat postingsFormat() { return postings; } Index: lucene/codecs/src/test/org/apache/lucene/codecs/appending/TestAppendingCodec.java =================================================================== --- lucene/codecs/src/test/org/apache/lucene/codecs/appending/TestAppendingCodec.java (revision 1391096) +++ lucene/codecs/src/test/org/apache/lucene/codecs/appending/TestAppendingCodec.java (working copy) @@ -21,7 +21,6 @@ import java.util.Random; import org.apache.lucene.analysis.MockAnalyzer; -import org.apache.lucene.codecs.appending.AppendingCodec; import org.apache.lucene.document.Document; import org.apache.lucene.document.FieldType; import org.apache.lucene.document.TextField; @@ -34,8 +33,8 @@ import org.apache.lucene.index.MultiFields; import org.apache.lucene.index.StoredDocument; import org.apache.lucene.index.Terms; +import org.apache.lucene.index.TermsEnum; import org.apache.lucene.index.TermsEnum.SeekStatus; -import org.apache.lucene.index.TermsEnum; import org.apache.lucene.index.TieredMergePolicy; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.store.Directory; @@ -45,7 +44,6 @@ import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.Version; public class TestAppendingCodec extends LuceneTestCase { @@ -111,7 +109,7 @@ public void testCodec() throws Exception { Directory dir = new AppendingRAMDirectory(random(), new RAMDirectory()); - IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_40, new MockAnalyzer(random())); + IndexWriterConfig cfg = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())); cfg.setCodec(new AppendingCodec()); ((TieredMergePolicy)cfg.getMergePolicy()).setUseCompoundFile(false); @@ -153,7 +151,7 @@ public void testCompoundFile() throws Exception { Directory dir = new AppendingRAMDirectory(random(), new RAMDirectory()); - IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_40, new MockAnalyzer(random())); + IndexWriterConfig cfg = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())); TieredMergePolicy mp = new TieredMergePolicy(); mp.setUseCompoundFile(true); mp.setNoCFSRatio(1.0); Index: lucene/core/src/java/org/apache/lucene/codecs/Codec.java =================================================================== --- lucene/core/src/java/org/apache/lucene/codecs/Codec.java (revision 1391096) +++ lucene/core/src/java/org/apache/lucene/codecs/Codec.java (working copy) @@ -30,8 +30,10 @@ * written into the index. In order for the segment to be read, the * name must resolve to your implementation via {@link #forName(String)}. * This method uses Java's - * {@link ServiceLoader Service Provider Interface} to resolve codec names. + * {@link ServiceLoader Service Provider Interface} (SPI) to resolve codec names. *

+ * If you implement your own codec, make sure that it has a no-arg constructor + * so SPI can load it. * @see ServiceLoader */ public abstract class Codec implements NamedSPILoader.NamedSPI { @@ -49,7 +51,7 @@ * SPI mechanism (registered in META-INF/ of your jar file, etc). * @param name must be all ascii alphanumeric, and less than 128 characters in length. */ - public Codec(String name) { + protected Codec(String name) { NamedSPILoader.checkServiceName(name); this.name = name; } @@ -86,11 +88,19 @@ /** looks up a codec by name */ public static Codec forName(String name) { + if (loader == null) { + throw new IllegalStateException("You called Codec.forName() before all Codecs could be initialized. "+ + "This happens likely if you call it from a Codec's ctor."); + } return loader.lookup(name); } /** returns a list of all available codec names */ public static Set availableCodecs() { + if (loader == null) { + throw new IllegalStateException("You called Codec.availableCodecs() before all Codecs could be initialized. "+ + "This happens likely if you call it from a Codec's ctor."); + } return loader.availableServices(); } Index: lucene/core/src/java/org/apache/lucene/codecs/FilterCodec.java =================================================================== --- lucene/core/src/java/org/apache/lucene/codecs/FilterCodec.java (revision 1391096) +++ lucene/core/src/java/org/apache/lucene/codecs/FilterCodec.java (working copy) @@ -27,71 +27,72 @@ * public final class CustomCodec extends FilterCodec { * * public CustomCodec() { - * super("CustomCodec"); + * super("CustomCodec", new Lucene40Codec()); * } * - * public Codec delegate() { - * return Codec.forName("Lucene40"); - * } - * * public LiveDocsFormat liveDocsFormat() { * return new CustomLiveDocsFormat(); * } * * } * + * + *

Please note: Don't call {@link Codec#forName} from + * the no-arg constructor of your own codec. When the SPI framework + * loads your own Codec as SPI component, SPI has not yet fully initialized! + * If you want to extend another Codec, instantiate it directly by calling + * its constructor. + * + * @lucene.experimental */ public abstract class FilterCodec extends Codec { + protected final Codec delegate; + /** Sole constructor. */ - public FilterCodec(String name) { + protected FilterCodec(String name, Codec delegate) { super(name); + this.delegate = delegate; } - /** - * Return the codec that is responsible for providing default format - * implementations. - */ - protected abstract Codec delegate(); - @Override public DocValuesFormat docValuesFormat() { - return delegate().docValuesFormat(); + return delegate.docValuesFormat(); } @Override public FieldInfosFormat fieldInfosFormat() { - return delegate().fieldInfosFormat(); + return delegate.fieldInfosFormat(); } @Override public LiveDocsFormat liveDocsFormat() { - return delegate().liveDocsFormat(); + return delegate.liveDocsFormat(); } @Override public NormsFormat normsFormat() { - return delegate().normsFormat(); + return delegate.normsFormat(); } @Override public PostingsFormat postingsFormat() { - return delegate().postingsFormat(); + return delegate.postingsFormat(); } @Override public SegmentInfoFormat segmentInfoFormat() { - return delegate().segmentInfoFormat(); + return delegate.segmentInfoFormat(); } @Override public StoredFieldsFormat storedFieldsFormat() { - return delegate().storedFieldsFormat(); + return delegate.storedFieldsFormat(); } @Override public TermVectorsFormat termVectorsFormat() { - return delegate().termVectorsFormat(); + return delegate.termVectorsFormat(); } } Index: lucene/core/src/java/org/apache/lucene/codecs/PostingsFormat.java =================================================================== --- lucene/core/src/java/org/apache/lucene/codecs/PostingsFormat.java (revision 1391096) +++ lucene/core/src/java/org/apache/lucene/codecs/PostingsFormat.java (working copy) @@ -33,8 +33,10 @@ * written into the index in certain configurations. In order for the segment * to be read, the name must resolve to your implementation via {@link #forName(String)}. * This method uses Java's - * {@link ServiceLoader Service Provider Interface} to resolve codec names. + * {@link ServiceLoader Service Provider Interface} (SPI) to resolve format names. *

+ * If you implement your own format, make sure that it has a no-arg constructor + * so SPI can load it. * @see ServiceLoader * @lucene.experimental */ public abstract class PostingsFormat implements NamedSPILoader.NamedSPI { @@ -91,11 +93,19 @@ /** looks up a format by name */ public static PostingsFormat forName(String name) { + if (loader == null) { + throw new IllegalStateException("You called PostingsFormat.forName() before all formats could be initialized. "+ + "This happens likely if you call it from a Codec's ctor."); + } return loader.lookup(name); } /** returns a list of all available format names */ public static Set availablePostingsFormats() { + if (loader == null) { + throw new IllegalStateException("You called PostingsFormat.availablePostingsFormats() before all formats could be initialized. "+ + "This happens likely if you call it from a PostingsFormat's ctor."); + } return loader.availableServices(); } Index: lucene/core/src/test/org/apache/lucene/index/TestAddIndexes.java =================================================================== --- lucene/core/src/test/org/apache/lucene/index/TestAddIndexes.java (revision 1391096) +++ lucene/core/src/test/org/apache/lucene/index/TestAddIndexes.java (working copy) @@ -1109,13 +1109,8 @@ private static final class UnRegisteredCodec extends FilterCodec { public UnRegisteredCodec() { - super("NotRegistered"); + super("NotRegistered", new Lucene40Codec()); } - - @Override - protected Codec delegate() { - return Codec.forName("Lucene40"); - } } /* Index: lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java (revision 1391096) +++ lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java (working copy) @@ -17,7 +17,6 @@ * limitations under the License. */ -import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.FilterCodec; import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.TermVectorsFormat; @@ -32,15 +31,10 @@ private final TermVectorsFormat vectors = new AssertingTermVectorsFormat(); public AssertingCodec() { - super("Asserting"); + super("Asserting", new Lucene40Codec()); } @Override - protected Codec delegate() { - return Codec.forName("Lucene40"); - } - - @Override public PostingsFormat postingsFormat() { return postings; }