Index: src/java/org/apache/lucene/index/FieldsReader.java
===================================================================
--- src/java/org/apache/lucene/index/FieldsReader.java	(revision 917019)
+++ src/java/org/apache/lucene/index/FieldsReader.java	Sat Mar 13 20:32:42 CET 2010
@@ -18,7 +18,6 @@
  */
 
 import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.document.AbstractField;
 import org.apache.lucene.document.CompressionTools;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
@@ -316,7 +315,7 @@
       Field.Index index = Field.Index.toIndex(fi.isIndexed, tokenize);
       Field.TermVector termVector = Field.TermVector.toTermVector(fi.storeTermVector, fi.storeOffsetWithTermVector, fi.storePositionWithTermVector);
 
-      AbstractField f;
+      Field f;
       if (compressed) {
         int toRead = fieldsStream.readVInt();
         long pointer = fieldsStream.getFilePointer();
@@ -361,7 +360,7 @@
       Field.Index index = Field.Index.toIndex(fi.isIndexed, tokenize);
       Field.TermVector termVector = Field.TermVector.toTermVector(fi.storeTermVector, fi.storeOffsetWithTermVector, fi.storePositionWithTermVector);
 
-      AbstractField f;
+      Field f;
       if (compressed) {
         int toRead = fieldsStream.readVInt();
 
@@ -408,7 +407,7 @@
    * A Lazy implementation of Fieldable that differs loading of fields until asked for, instead of when the Document is
    * loaded.
    */
-  private class LazyField extends AbstractField implements Fieldable {
+  private class LazyField extends Field implements Fieldable {
     private int toRead;
     private long pointer;
     /** @deprecated Only kept for backward-compatbility with <3.0 indexes. Will be removed in 4.0. */
@@ -416,7 +415,7 @@
     private boolean isCompressed;
 
     public LazyField(String name, Field.Store store, int toRead, long pointer, boolean isBinary, boolean isCompressed) {
-      super(name, store, Field.Index.NO, Field.TermVector.NO);
+      super(name, null, store, Field.Index.NO, Field.TermVector.NO);
       this.toRead = toRead;
       this.pointer = pointer;
       this.isBinary = isBinary;
@@ -427,7 +426,7 @@
     }
 
     public LazyField(String name, Field.Store store, Field.Index index, Field.TermVector termVector, int toRead, long pointer, boolean isBinary, boolean isCompressed) {
-      super(name, store, index, termVector);
+      super(name, null, store, index, termVector);
       this.toRead = toRead;
       this.pointer = pointer;
       this.isBinary = isBinary;
Index: src/java/org/apache/lucene/document/Field.java
===================================================================
--- src/java/org/apache/lucene/document/Field.java	(revision 893177)
+++ src/java/org/apache/lucene/document/Field.java	Sat Mar 20 23:49:50 CET 2010
@@ -25,78 +25,118 @@
 import java.io.Serializable;
 
 /**
-  A field is a section of a Document.  Each field has two parts, a name and a
-  value.  Values may be free text, provided as a String or as a Reader, or they
-  may be atomic keywords, which are not further processed.  Such keywords may
-  be used to represent dates, urls, etc.  Fields are optionally stored in the
-  index, so that they may be returned with hits on the document.
+ * A field is a section of a Document.  Each field has two parts, a name and a
+ * value.  Values may be free text, provided as a String or as a Reader, or they
+ * may be atomic keywords, which are not further processed.  Such keywords may
+ * be used to represent dates, urls, etc.  Fields are optionally stored in the
+ * index, so that they may be returned with hits on the document.
-  */
+ */
+public class Field extends AbstractField implements Fieldable, Serializable {
-
+  
-public final class Field extends AbstractField implements Fieldable, Serializable {
-  
-  /** Specifies whether and how a field should be stored. */
+  /**
+   * Specifies whether and how a field should be stored.
+   */
   public static enum Store {
 
-    /** Store the original field value in the index. This is useful for short texts
+    /**
+     * Store the original field value in the index. This is useful for short texts
      * like a document's title which should be displayed with the results. The
      * value is stored in its original form, i.e. no analyzer is used before it is
      * stored.
      */
     YES {
       @Override
-      public boolean isStored() { return true; }
+      public boolean isStored() {
+        return true;
+      }
     },
 
-    /** Do not store the field value in the index. */
+    /**
+     * Do not store the field value in the index.
+     */
     NO {
       @Override
-      public boolean isStored() { return false; }
+      public boolean isStored() {
+        return false;
+      }
     };
 
     public abstract boolean isStored();
   }
 
-  /** Specifies whether and how a field should be indexed. */
+  /**
+   * Specifies whether and how a field should be indexed.
+   */
   public static enum Index {
 
-    /** Do not index the field value. This field can thus not be searched,
+    /**
+     * Do not index the field value. This field can thus not be searched,
      * but one can still access its contents provided it is
-     * {@link Field.Store stored}. */
+     * {@link Field.Store stored}.
+     */
     NO {
       @Override
-      public boolean isIndexed()  { return false; }
+      public boolean isIndexed() {
+        return false;
+      }
+
       @Override
-      public boolean isAnalyzed() { return false; }
+      public boolean isAnalyzed() {
+        return false;
+      }
+
       @Override
-      public boolean omitNorms()  { return true;  }   
+      public boolean omitNorms() {
+        return true;
+      }
     },
 
-    /** Index the tokens produced by running the field's
+    /**
+     * Index the tokens produced by running the field's
      * value through an Analyzer.  This is useful for
-     * common text. */
+     * common text.
+     */
     ANALYZED {
       @Override
-      public boolean isIndexed()  { return true;  }
+      public boolean isIndexed() {
+        return true;
+      }
+
       @Override
-      public boolean isAnalyzed() { return true;  }
+      public boolean isAnalyzed() {
+        return true;
+      }
+
       @Override
-      public boolean omitNorms()  { return false; }   	
+      public boolean omitNorms()  {
+        return false;
+      }
     },
 
-    /** Index the field's value without using an Analyzer, so it can be searched.
+    /**
+     * Index the field's value without using an Analyzer, so it can be searched.
      * As no analyzer is used the value will be stored as a single term. This is
      * useful for unique Ids like product numbers.
      */
     NOT_ANALYZED {
       @Override
-      public boolean isIndexed()  { return true;  }
+      public boolean isIndexed() {
+        return true;
+      }
+
       @Override
-      public boolean isAnalyzed() { return false; }
+      public boolean isAnalyzed() {
+        return false;
+      }
+
       @Override
-      public boolean omitNorms()  { return false; }   	
+      public boolean omitNorms() {
+        return false;
+      }   	
     },
 
-    /** Expert: Index the field's value without an Analyzer,
+    /**
+     * Expert: Index the field's value without an Analyzer,
      * and also disable the storing of norms.  Note that you
      * can also separately enable/disable norms by calling
      * {@link Field#setOmitNorms}.  No norms means that
@@ -109,36 +149,68 @@
      * have no effect.  In other words, for this to have the
      * above described effect on a field, all instances of
      * that field must be indexed with NOT_ANALYZED_NO_NORMS
-     * from the beginning. */
+     * from the beginning.
+     */
     NOT_ANALYZED_NO_NORMS {
       @Override
-      public boolean isIndexed()  { return true;  }
+      public boolean isIndexed() {
+        return true;
+      }
+
       @Override
-      public boolean isAnalyzed() { return false; }
+      public boolean isAnalyzed() {
+        return false;
+      }
+
       @Override
-      public boolean omitNorms()  { return true;  }   	
+      public boolean omitNorms() {
+        return true;  
+      }
     },
 
-    /** Expert: Index the tokens produced by running the
+    /**
+     * Expert: Index the tokens produced by running the
      *  field's value through an Analyzer, and also
      *  separately disable the storing of norms.  See
      *  {@link #NOT_ANALYZED_NO_NORMS} for what norms are
-     *  and why you may want to disable them. */
+     *  and why you may want to disable them.
+     */
     ANALYZED_NO_NORMS {
       @Override
-      public boolean isIndexed()  { return true;  }
+      public boolean isIndexed() {
+        return true;
+      }
+
       @Override
-      public boolean isAnalyzed() { return true;  }
+      public boolean isAnalyzed() {
+        return true;
+      }
+
       @Override
-      public boolean omitNorms()  { return true;  }   	
+      public boolean omitNorms() {
+        return true;
+      }   	
     };
 
-    /** Get the best representation of the index given the flags. */
+    /**
+     * Get the best representation of the index given the flags.
+     *
+     * @param indexed Whether the field is to be indexed
+     * @param analyzed Whether the field is to be analyzed
+     * @return Index representing the given flags
+     */
     public static Index toIndex(boolean indexed, boolean analyzed) {
       return toIndex(indexed, analyzed, false);
     }
 
-    /** Expert: Get the best representation of the index given the flags. */
+    /**
+     * Expert: Get the best representation of the index given the flags.
+     *
+     * @param indexed Whether the field is to be indexed
+     * @param analyzed Whether the field is to be analyzed
+     * @param omitNorms Whether norms should be omitted
+     * @return Index representation of the given flags
+     */
     public static Index toIndex(boolean indexed, boolean analyzed, boolean omitNorms) {
 
       // If it is not indexed nothing else matters
@@ -166,10 +238,13 @@
     public abstract boolean omitNorms();  	
   }
 
-  /** Specifies whether and how a field should have term vectors. */
+  /**
+   * Specifies whether and how a field should have term vectors.
+   */
   public static enum TermVector {
     
-    /** Do not store term vectors. 
+    /**
+     * Do not store term vectors.
      */
     NO {
       @Override
@@ -180,8 +255,10 @@
       public boolean withOffsets()   { return false; }
     },
     
-    /** Store the term vectors of each document. A term vector is a list
-     * of the document's terms and their number of occurrences in that document. */
+    /**
+     * Store the term vectors of each document. A term vector is a list
+     * of the document's terms and their number of occurrences in that document.
+     */
     YES {
       @Override
       public boolean isStored()      { return true;  }
@@ -235,7 +312,14 @@
       public boolean withOffsets()   { return true;  }
     };
 
-    /** Get the best representation of a TermVector given the flags. */
+    /**
+     * Get the best representation of a TermVector given the flags.
+     *
+     * @param stored Whether the term vectors are to be stored
+     * @param withOffsets Whether term vectors with offsets are to be stored
+     * @param withPositions Whether term vectors with positions are to be stored
+     * @return TermVector representation of the given flags 
+     */
     public static TermVector toTermVector(boolean stored, boolean withOffsets, boolean withPositions) {
 
       // If it is not stored, nothing else matters.
@@ -260,164 +344,113 @@
     public abstract boolean withPositions();
     public abstract boolean withOffsets();
   }
-  
+
+  protected String name;
+  protected boolean storeTermVector = false;
+  protected boolean storeOffsetWithTermVector = false;
+  protected boolean storePositionWithTermVector = false;
+  protected boolean omitNorms = false;
+  protected boolean isStored = false;
+  protected boolean isIndexed = true;
+  protected boolean isTokenized = true;
+  protected boolean isBinary = false;
+  protected boolean lazy = false;
+  protected boolean omitTermFreqAndPositions = false;
+  protected float boost = 1.0f;
+  // the data object for all different kind of field values
+  protected Object fieldsData = null;
+  // pre-analyzed tokenStream for indexed fields
+  protected TokenStream tokenStream;
+  // length/offset for all primitive types
+  protected int binaryLength;
+  protected int binaryOffset;
-  
+
-  /** The value of the field as a String, or null.  If null, the Reader value or
-   * binary value is used.  Exactly one of stringValue(),
-   * readerValue(), and getBinaryValue() must be set. */
-  public String stringValue()   { return fieldsData instanceof String ? (String)fieldsData : null; }
-  
-  /** The value of the field as a Reader, or null.  If null, the String value or
-   * binary value is used.  Exactly one of stringValue(),
-   * readerValue(), and getBinaryValue() must be set. */
-  public Reader readerValue()   { return fieldsData instanceof Reader ? (Reader)fieldsData : null; }
-    
-  /** The TokesStream for this field to be used when indexing, or null.  If null, the Reader value
-   * or String value is analyzed to produce the indexed tokens. */
-  public TokenStream tokenStreamValue()   { return tokenStream; }
-  
-
-  /** <p>Expert: change the value of this field.  This can
-   *  be used during indexing to re-use a single Field
-   *  instance to improve indexing speed by avoiding GC cost
-   *  of new'ing and reclaiming Field instances.  Typically
-   *  a single {@link Document} instance is re-used as
-   *  well.  This helps most on small documents.</p>
-   * 
-   *  <p>Each Field instance should only be used once
-   *  within a single {@link Document} instance.  See <a
-   *  href="http://wiki.apache.org/lucene-java/ImproveIndexingSpeed">ImproveIndexingSpeed</a>
-   *  for details.</p> */
-  public void setValue(String value) {
-    if (isBinary) {
-      throw new IllegalArgumentException("cannot set a String value on a binary field");
-    }
-    fieldsData = value;
-  }
-
-  /** Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>. */
-  public void setValue(Reader value) {
-    if (isBinary) {
-      throw new IllegalArgumentException("cannot set a Reader value on a binary field");
-    }
-    if (isStored) {
-      throw new IllegalArgumentException("cannot set a Reader value on a stored field");
-    }
-    fieldsData = value;
-  }
-
-  /** Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>. */
-  public void setValue(byte[] value) {
-    if (!isBinary) {
-      throw new IllegalArgumentException("cannot set a byte[] value on a non-binary field");
-    }
-    fieldsData = value;
-    binaryLength = value.length;
-    binaryOffset = 0;
-  }
-
-  /** Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>. */
-  public void setValue(byte[] value, int offset, int length) {
-    if (!isBinary) {
-      throw new IllegalArgumentException("cannot set a byte[] value on a non-binary field");
-    }
-    fieldsData = value;
-    binaryLength = length;
-    binaryOffset = offset;
-  }
-  
-  /** Expert: sets the token stream to be used for indexing and causes isIndexed() and isTokenized() to return true.
-   *  May be combined with stored values from stringValue() or getBinaryValue() */
-  public void setTokenStream(TokenStream tokenStream) {
-    this.isIndexed = true;
-    this.isTokenized = true;
-    this.tokenStream = tokenStream;
-  }
-
   /**
    * Create a field by specifying its name, value and how it will
    * be saved in the index. Term vectors will not be stored in the index.
-   * 
+   *
    * @param name The name of the field
    * @param value The string to process
    * @param store Whether <code>value</code> should be stored in the index
    * @param index Whether the field should be indexed, and if so, if it should
-   *  be tokenized before indexing 
+   *  be tokenized before indexing
    * @throws NullPointerException if name or value is <code>null</code>
-   * @throws IllegalArgumentException if the field is neither stored nor indexed 
+   * @throws IllegalArgumentException if the field is neither stored nor indexed
    */
   public Field(String name, String value, Store store, Index index) {
     this(name, value, store, index, TermVector.NO);
   }
-  
+
   /**
    * Create a field by specifying its name, value and how it will
    * be saved in the index.
-   * 
+   *
    * @param name The name of the field
    * @param value The string to process
    * @param store Whether <code>value</code> should be stored in the index
    * @param index Whether the field should be indexed, and if so, if it should
-   *  be tokenized before indexing 
+   *  be tokenized before indexing
    * @param termVector Whether term vector should be stored
    * @throws NullPointerException if name or value is <code>null</code>
    * @throws IllegalArgumentException in any of the following situations:
-   * <ul> 
-   *  <li>the field is neither stored nor indexed</li> 
+   * <ul>
+   *  <li>the field is neither stored nor indexed</li>
    *  <li>the field is not indexed but termVector is <code>TermVector.YES</code></li>
-   * </ul> 
-   */ 
+   * </ul>
+   */
   public Field(String name, String value, Store store, Index index, TermVector termVector) {
     this(name, true, value, store, index, termVector);
   }
-  
+
   /**
    * Create a field by specifying its name, value and how it will
    * be saved in the index.
-   * 
+   *
    * @param name The name of the field
    * @param internName Whether to .intern() name or not
    * @param value The string to process
    * @param store Whether <code>value</code> should be stored in the index
    * @param index Whether the field should be indexed, and if so, if it should
-   *  be tokenized before indexing 
+   *  be tokenized before indexing
    * @param termVector Whether term vector should be stored
    * @throws NullPointerException if name or value is <code>null</code>
    * @throws IllegalArgumentException in any of the following situations:
-   * <ul> 
-   *  <li>the field is neither stored nor indexed</li> 
+   * <ul>
+   *  <li>the field is neither stored nor indexed</li>
    *  <li>the field is not indexed but termVector is <code>TermVector.YES</code></li>
-   * </ul> 
-   */ 
+   * </ul>
+   */
   public Field(String name, boolean internName, String value, Store store, Index index, TermVector termVector) {
-    if (name == null)
+    if (name == null) {
       throw new NullPointerException("name cannot be null");
-    if (value == null)
-      throw new NullPointerException("value cannot be null");
-    if (name.length() == 0 && value.length() == 0)
+    }
+    if (name.length() == 0 && (value == null || value.length() == 0)) {
       throw new IllegalArgumentException("name and value cannot both be empty");
-    if (index == Index.NO && store == Store.NO)
+    }
+    if (index == Index.NO && store == Store.NO) {
       throw new IllegalArgumentException("it doesn't make sense to have a field that "
          + "is neither indexed nor stored");
-    if (index == Index.NO && termVector != TermVector.NO)
+    }
+    if (index == Index.NO && termVector != TermVector.NO) {
       throw new IllegalArgumentException("cannot store term vector information "
          + "for a field that is not indexed");
+    }
-          
+
-    if (internName) // field names are optionally interned
+    if (internName) { // field names are optionally interned
       name = StringHelper.intern(name);
+    }
-    
-    this.name = name; 
+
+    this.name = name;
-    
     this.fieldsData = value;
 
     this.isStored = store.isStored();
-   
     this.isIndexed = index.isIndexed();
     this.isTokenized = index.isAnalyzed();
     this.omitNorms = index.omitNorms();
+
     if (index == Index.NO) {
       this.omitTermFreqAndPositions = false;
-    }    
+    }
 
     this.isBinary = false;
 
@@ -429,7 +462,7 @@
    * not be stored.  The Reader is read only when the Document is added to the index,
    * i.e. you may not close the Reader until {@link IndexWriter#addDocument(Document)}
    * has been called.
-   * 
+   *
    * @param name The name of the field
    * @param reader The reader with the content
    * @throws NullPointerException if name or reader is <code>null</code>
@@ -439,32 +472,32 @@
   }
 
   /**
-   * Create a tokenized and indexed field that is not stored, optionally with 
+   * Create a tokenized and indexed field that is not stored, optionally with
    * storing term vectors.  The Reader is read only when the Document is added to the index,
    * i.e. you may not close the Reader until {@link IndexWriter#addDocument(Document)}
    * has been called.
-   * 
+   *
    * @param name The name of the field
    * @param reader The reader with the content
    * @param termVector Whether term vector should be stored
    * @throws NullPointerException if name or reader is <code>null</code>
-   */ 
+   */
   public Field(String name, Reader reader, TermVector termVector) {
-    if (name == null)
+    if (name == null) {
       throw new NullPointerException("name cannot be null");
-    if (reader == null)
+    }
+    if (reader == null) {
       throw new NullPointerException("reader cannot be null");
+    }
-    
+
-    this.name = StringHelper.intern(name);        // field names are interned
+    this.name = StringHelper.intern(name); // field names are interned
     this.fieldsData = reader;
-    
+
     this.isStored = false;
-    
     this.isIndexed = true;
     this.isTokenized = true;
-    
     this.isBinary = false;
-    
+
     setStoreTermVector(termVector);
   }
 
@@ -474,55 +507,55 @@
    * The TokenStream is read only when the Document is added to the index,
    * i.e. you may not close the TokenStream until {@link IndexWriter#addDocument(Document)}
    * has been called.
-   * 
+   *
    * @param name The name of the field
    * @param tokenStream The TokenStream with the content
    * @throws NullPointerException if name or tokenStream is <code>null</code>
-   */ 
+   */
   public Field(String name, TokenStream tokenStream) {
     this(name, tokenStream, TermVector.NO);
   }
-  
+
   /**
-   * Create a tokenized and indexed field that is not stored, optionally with 
+   * Create a tokenized and indexed field that is not stored, optionally with
    * storing term vectors.  This is useful for pre-analyzed fields.
    * The TokenStream is read only when the Document is added to the index,
    * i.e. you may not close the TokenStream until {@link IndexWriter#addDocument(Document)}
    * has been called.
-   * 
+   *
    * @param name The name of the field
    * @param tokenStream The TokenStream with the content
    * @param termVector Whether term vector should be stored
    * @throws NullPointerException if name or tokenStream is <code>null</code>
-   */ 
+   */
   public Field(String name, TokenStream tokenStream, TermVector termVector) {
-    if (name == null)
+    if (name == null) {
       throw new NullPointerException("name cannot be null");
-    if (tokenStream == null)
+    }
+    if (tokenStream == null) {
       throw new NullPointerException("tokenStream cannot be null");
+    }
-    
+
-    this.name = StringHelper.intern(name);        // field names are interned
+    this.name = StringHelper.intern(name); // field names are interned
     this.fieldsData = null;
     this.tokenStream = tokenStream;
 
     this.isStored = false;
-    
     this.isIndexed = true;
     this.isTokenized = true;
-    
     this.isBinary = false;
-    
+
     setStoreTermVector(termVector);
   }
 
-  
+
   /**
    * Create a stored field with binary value. Optionally the value may be compressed.
-   * 
+   *
    * @param name The name of the field
    * @param value The binary value
    * @param store Must be Store.YES
-   * @throws IllegalArgumentException if store is <code>Store.NO</code> 
+   * @throws IllegalArgumentException if store is <code>Store.NO</code>
    * @deprecated Use {@link #Field(String, byte[]) instead}
    */
   @Deprecated
@@ -536,7 +569,7 @@
 
   /**
    * Create a stored field with binary value. Optionally the value may be compressed.
-   * 
+   *
    * @param name The name of the field
    * @param value The binary value
    */
@@ -546,13 +579,13 @@
 
   /**
    * Create a stored field with binary value. Optionally the value may be compressed.
-   * 
+   *
    * @param name The name of the field
    * @param value The binary value
    * @param offset Starting offset in value where this Field's bytes are
    * @param length Number of bytes to use for this Field, starting at offset
    * @param store How <code>value</code> should be stored (compressed or not)
-   * @throws IllegalArgumentException if store is <code>Store.NO</code> 
+   * @throws IllegalArgumentException if store is <code>Store.NO</code>
    * @deprecated Use {@link #Field(String, byte[], int, int) instead}
    */
   @Deprecated
@@ -566,32 +599,349 @@
 
   /**
    * Create a stored field with binary value. Optionally the value may be compressed.
-   * 
+   *
    * @param name The name of the field
    * @param value The binary value
    * @param offset Starting offset in value where this Field's bytes are
    * @param length Number of bytes to use for this Field, starting at offset
    */
   public Field(String name, byte[] value, int offset, int length) {
-
-    if (name == null)
+    if (name == null) {
       throw new IllegalArgumentException("name cannot be null");
-    if (value == null)
-      throw new IllegalArgumentException("value cannot be null");
+    }
-    
+
-    this.name = StringHelper.intern(name);        // field names are interned
+    this.name = StringHelper.intern(name);  // field names are interned
+    this.fieldsData = value;
+
+    this.isStored = true;
+    this.isIndexed = false;
+    this.isTokenized = false;
+    this.omitTermFreqAndPositions = false;
+    this.omitNorms = true;
+
+    this.isBinary = true;
+    this.binaryLength = length;
+    this.binaryOffset = offset;
+
+    setStoreTermVector(TermVector.NO);
+  }
+  
+  /**
+   * The value of the field as a String, or null.  If null, the Reader value or
+   * binary value is used.  Exactly one of stringValue(),
+   * readerValue(), and getBinaryValue() must be set.
+   */
+  public String stringValue() {
+    return fieldsData instanceof String ? (String)fieldsData : null;
+  }
+  
+  /**
+   * The value of the field as a Reader, or null.  If null, the String value or
+   * binary value is used.  Exactly one of stringValue(),
+   * readerValue(), and getBinaryValue() must be set.
+   */
+  public Reader readerValue() {
+    return fieldsData instanceof Reader ? (Reader)fieldsData : null;
+  }
+
+  /**
+   * The TokesStream for this field to be used when indexing, or null.  If null, the Reader value
+   * or String value is analyzed to produce the indexed tokens.
+   */
+  public TokenStream tokenStreamValue()   {
+    return tokenStream;
+  }
+  
+  /**
+   * <p>Expert: change the value of this field.  This can
+   *  be used during indexing to re-use a single Field
+   *  instance to improve indexing speed by avoiding GC cost
+   *  of new'ing and reclaiming Field instances.  Typically
+   *  a single {@link Document} instance is re-used as
+   *  well.  This helps most on small documents.</p>
+   * 
+   *  <p>Each Field instance should only be used once
+   *  within a single {@link Document} instance.  See <a
+   *  href="http://wiki.apache.org/lucene-java/ImproveIndexingSpeed">ImproveIndexingSpeed</a>
+   *  for details.</p>
+   *
+   * @param value New value for the Field
+   */
+  public void setValue(String value) {
+    if (isBinary) {
+      throw new IllegalArgumentException("cannot set a String value on a binary field");
+    }
     fieldsData = value;
+  }
-    
+
-    isStored = true;
-    isIndexed   = false;
-    isTokenized = false;
-    omitTermFreqAndPositions = false;
-    omitNorms = true;
+  /**
+   * Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>.
+   *
+   * @param value New Reader value for the Field
+   */
+  public void setValue(Reader value) {
+    if (isBinary) {
+      throw new IllegalArgumentException("cannot set a Reader value on a binary field");
+    }
+    if (isStored) {
+      throw new IllegalArgumentException("cannot set a Reader value on a stored field");
+    }
+    fieldsData = value;
+  }
-    
+
-    isBinary    = true;
+  /**
+   * Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>.
+   *
+   * @param value New value for the field
+   */
+  public void setValue(byte[] value) {
+    if (!isBinary) {
+      throw new IllegalArgumentException("cannot set a byte[] value on a non-binary field");
+    }
+    fieldsData = value;
+    binaryLength = value.length;
+    binaryOffset = 0;
+  }
+
+  /**
+   * Expert: change the value of this field.  See <a href="#setValue(java.lang.String)">setValue(String)</a>.
+   *
+   * @param value byte array to take the new value from
+   * @param offset Offset in the array that the new value begins at
+   * @param length Length in the array that the new value is 
+   */
+  public void setValue(byte[] value, int offset, int length) {
+    if (!isBinary) {
+      throw new IllegalArgumentException("cannot set a byte[] value on a non-binary field");
+    }
+    fieldsData = value;
     binaryLength = length;
     binaryOffset = offset;
+  }
-    
+  
-    setStoreTermVector(TermVector.NO);
+  /**
+   * Expert: sets the token stream to be used for indexing and causes isIndexed() and isTokenized() to return true.
+   *  May be combined with stored values from stringValue() or getBinaryValue()
+   *
+   * @param tokenStream New TokenStream for the field
+   */
+  public void setTokenStream(TokenStream tokenStream) {
+    this.isIndexed = true;
+    this.isTokenized = true;
+    this.tokenStream = tokenStream;
   }
+
+  /**
+   * Sets the term vector related properties to the values defined in the given TermVector
+   *
+   * @param termVector TermVector representation of term vector configuration
+   */
+  protected void setStoreTermVector(Field.TermVector termVector) {
+    this.storeTermVector = termVector.isStored();
+    this.storePositionWithTermVector = termVector.withPositions();
+    this.storeOffsetWithTermVector = termVector.withOffsets();
-}
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setBoost(float boost) {
+    this.boost = boost;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public float getBoost() {
+    return boost;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String name() {
+    return name;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isStored() {
+    return isStored;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isIndexed() {
+    return isIndexed;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isTokenized() {
+    return isTokenized;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isTermVectorStored() {
+    return storeTermVector;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isStoreOffsetWithTermVector() {
+    return storeOffsetWithTermVector;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isStorePositionWithTermVector() {
+    return storePositionWithTermVector;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isBinary() {
+    return isBinary;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean getOmitNorms() {
+    return omitNorms;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setOmitNorms(boolean omitNorms) {
+    this.omitNorms = omitNorms;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isLazy() {
+    return lazy;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getBinaryOffset() {
+    return binaryOffset;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getBinaryLength() {
+    if (isBinary) {
+      return binaryLength;
+    }
+    if (fieldsData instanceof byte[]) {
+      return ((byte[]) fieldsData).length;
+    }
+    return 0;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] getBinaryValue() {
+    return getBinaryValue(null);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] getBinaryValue(byte[] result) {
+    return isBinary || fieldsData instanceof byte[] ? (byte[]) fieldsData : null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean getOmitTermFreqAndPositions() {
+    return omitTermFreqAndPositions;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setOmitTermFreqAndPositions(boolean omitTermFreqAndPositions) {
+    this.omitTermFreqAndPositions = omitTermFreqAndPositions;
+  }
+
+  /**
+   * Prints a Field for human consumption.
+   */
+  @Override
+  public final String toString() {
+    StringBuilder result = new StringBuilder();
+    if (isStored) {
+      result.append("stored");
+    }
+    if (isIndexed) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("indexed");
+    }
+    if (isTokenized) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("tokenized");
+    }
+    if (storeTermVector) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("termVector");
+    }
+    if (storeOffsetWithTermVector) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("termVectorOffsets");
+    }
+    if (storePositionWithTermVector) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("termVectorPosition");
+    }
+    if (isBinary) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append("binary");
+    }
+    if (omitNorms) {
+      result.append(",omitNorms");
+    }
+    if (omitTermFreqAndPositions) {
+      result.append(",omitTermFreqAndPositions");
+    }
+    if (lazy) {
+      result.append(",lazy");
+    }
+    result.append('<').append(name).append(':');
+
+    if (fieldsData != null && !lazy) {
+      result.append(fieldsData);
+    }
+
+    result.append('>');
+    return result.toString();
+  }
+}
Index: src/java/org/apache/lucene/index/CheckIndex.java
===================================================================
--- src/java/org/apache/lucene/index/CheckIndex.java	(revision 917019)
+++ src/java/org/apache/lucene/index/CheckIndex.java	Sat Mar 13 20:32:42 CET 2010
@@ -20,7 +20,7 @@
 import org.apache.lucene.store.FSDirectory;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IndexInput;
-import org.apache.lucene.document.AbstractField;  // for javadocs
+import org.apache.lucene.document.Field;  // for javadocs
 import org.apache.lucene.document.Document;
 
 import java.text.NumberFormat;
@@ -166,7 +166,7 @@
 
       /** True if at least one of the fields in this segment
        *  does not omitTermFreqAndPositions.
-       *  @see AbstractField#setOmitTermFreqAndPositions */
+       *  @see Field#setOmitTermFreqAndPositions */
       public boolean hasProx;
 
       /** Map that includes certain
Index: src/java/org/apache/lucene/document/NumericField.java
===================================================================
--- src/java/org/apache/lucene/document/NumericField.java	(revision 917019)
+++ src/java/org/apache/lucene/document/NumericField.java	Sat Mar 13 20:01:01 CET 2010
@@ -138,10 +138,8 @@
  *
  * @since 2.9
  */
-public final class NumericField extends AbstractField {
+public final class NumericField extends Field {
 
-  private final NumericTokenStream numericTS;
-
   /**
    * Creates a field for numeric values using the default <code>precisionStep</code>
    * {@link NumericUtils#PRECISION_STEP_DEFAULT} (4). The instance is not yet initialized with
@@ -193,16 +191,11 @@
    * @param index if the field should be indexed using {@link NumericTokenStream}
    */
   public NumericField(String name, int precisionStep, Field.Store store, boolean index) {
-    super(name, store, index ? Field.Index.ANALYZED_NO_NORMS : Field.Index.NO, Field.TermVector.NO);
+    super(name, null, store, index ? Field.Index.ANALYZED_NO_NORMS : Field.Index.NO, Field.TermVector.NO);
     setOmitTermFreqAndPositions(true);
-    numericTS = new NumericTokenStream(precisionStep);
+    tokenStream = new NumericTokenStream(precisionStep);
   }
-
+  
-  /** Returns a {@link NumericTokenStream} for indexing the numeric value. */
-  public TokenStream tokenStreamValue()   {
-    return isIndexed() ? numericTS : null;
-  }
-  
   /** Returns always <code>null</code> for numeric fields */
   @Override
   public byte[] getBinaryValue(byte[] result){
@@ -231,7 +224,7 @@
    * <code>document.add(new NumericField(name, precisionStep).setLongValue(value))</code>
    */
   public NumericField setLongValue(final long value) {
-    numericTS.setLongValue(value);
+    ((NumericTokenStream) tokenStream).setLongValue(value);
     fieldsData = Long.valueOf(value);
     return this;
   }
@@ -243,7 +236,7 @@
    * <code>document.add(new NumericField(name, precisionStep).setIntValue(value))</code>
    */
   public NumericField setIntValue(final int value) {
-    numericTS.setIntValue(value);
+    ((NumericTokenStream) tokenStream).setIntValue(value);
     fieldsData = Integer.valueOf(value);
     return this;
   }
@@ -255,7 +248,7 @@
    * <code>document.add(new NumericField(name, precisionStep).setDoubleValue(value))</code>
    */
   public NumericField setDoubleValue(final double value) {
-    numericTS.setDoubleValue(value);
+    ((NumericTokenStream) tokenStream).setDoubleValue(value);
     fieldsData = Double.valueOf(value);
     return this;
   }
@@ -267,9 +260,48 @@
    * <code>document.add(new NumericField(name, precisionStep).setFloatValue(value))</code>
    */
   public NumericField setFloatValue(final float value) {
-    numericTS.setFloatValue(value);
+    ((NumericTokenStream) tokenStream).setFloatValue(value);
     fieldsData = Float.valueOf(value);
     return this;
   }
 
+  /**
+   * An unsupported operation for NumericFields
+   */
+  @Override
+  public void setTokenStream(TokenStream tokenStream) {
+    throw new UnsupportedOperationException("Cannot set new TokenStreams in NumericFields");
-}
+  }
+
+  /**
+   * An unsupported operation for NumericFields
+   */
+  @Override
+  public void setValue(String value) {
+    throw new UnsupportedOperationException("Cannot set String values in NumericFields");
+  }
+
+  /**
+   * An unsupported operation for NumericFields
+   */
+  @Override
+  public void setValue(Reader value) {
+    throw new UnsupportedOperationException("Cannot set value through Readers in NumericFields");
+  }
+
+  /**
+   * An unsupported operation for NumericFields
+   */
+  @Override
+  public void setValue(byte[] value) {
+    throw new UnsupportedOperationException("Cannot set byte[] values in NumericFields");
+  }
+
+  /**
+   * An unsupported operation for NumericFields
+   */
+  @Override
+  public void setValue(byte[] value, int offset, int length) {
+    throw new UnsupportedOperationException("Cannot set byte[] values in NumericFields");
+  }
+}
Index: src/java/org/apache/lucene/document/AbstractField.java
===================================================================
--- src/java/org/apache/lucene/document/AbstractField.java	(revision 917019)
+++ src/java/org/apache/lucene/document/AbstractField.java	Sat Mar 13 20:27:07 CET 2010
@@ -24,8 +24,11 @@
 
 /**
  *
- *
+ * @deprecated The functionality of this class has been moved to {@link Field}
+ *             therefore subclasses should extend {@link Field}.  This class
+ *             will be removed in a future version.
  **/
+@Deprecated
 public abstract class AbstractField implements Fieldable {
 
   protected String name = "body";
@@ -122,16 +125,16 @@
   /** True iff the value of the field is to be stored in the index for return
     with search hits.  It is an error for this to be true if a field is
     Reader-valued. */
-  public final boolean  isStored()  { return isStored; }
+  public boolean  isStored()  { return isStored; }
 
   /** True iff the value of the field is to be indexed, so that it may be
     searched on. */
-  public final boolean  isIndexed()   { return isIndexed; }
+  public boolean  isIndexed()   { return isIndexed; }
 
   /** True iff the value of the field should be tokenized as text prior to
     indexing.  Un-tokenized fields are indexed as a single word and may not be
     Reader-valued. */
-  public final boolean  isTokenized()   { return isTokenized; }
+  public boolean  isTokenized()   { return isTokenized; }
 
   /** True iff the term or terms used to index this field are stored as a term
    *  vector, available from {@link org.apache.lucene.index.IndexReader#getTermFreqVector(int,String)}.
@@ -141,7 +144,7 @@
    *
    * @see org.apache.lucene.index.IndexReader#getTermFreqVector(int, String)
    */
-  public final boolean isTermVectorStored() { return storeTermVector; }
+  public boolean isTermVectorStored() { return storeTermVector; }
 
   /**
    * True iff terms are stored as term vector together with their offsets 
@@ -159,7 +162,7 @@
   }
 
   /** True iff the value of the filed is stored as binary */
-  public final boolean  isBinary() {
+  public boolean  isBinary() {
     return isBinary;
   }
 
@@ -237,7 +240,7 @@
 
   /** Prints a Field for human consumption. */
   @Override
-  public final String toString() {
+  public String toString() {
     StringBuilder result = new StringBuilder();
     if (isStored) {
       result.append("stored");
