Index: src/java/org/apache/lucene/analysis/tokenattributes/FlagsAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/FlagsAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/FlagsAttribute.java	(working copy)
@@ -31,7 +31,7 @@
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
 
  */
-public class FlagsAttribute extends Attribute implements Cloneable, Serializable {
+public class FlagsAttribute extends TokenAttribute implements Cloneable, Serializable {
   private int flags = 0;
   
   /**
Index: src/java/org/apache/lucene/analysis/tokenattributes/OffsetAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/OffsetAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/OffsetAttribute.java	(working copy)
@@ -29,7 +29,7 @@
  * The APIs introduced in these classes with Lucene 2.9 might change in the future. 
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
  */
-public class OffsetAttribute extends Attribute implements Cloneable, Serializable {
+public class OffsetAttribute extends TokenAttribute implements Cloneable, Serializable {
   private int startOffset;
   private int endOffset;
 
Index: src/java/org/apache/lucene/analysis/tokenattributes/PayloadAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/PayloadAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/PayloadAttribute.java	(working copy)
@@ -30,7 +30,7 @@
  * The APIs introduced in these classes with Lucene 2.9 might change in the future. 
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
  */
-public class PayloadAttribute extends Attribute implements Cloneable, Serializable {
+public class PayloadAttribute extends TokenAttribute implements Cloneable, Serializable {
   private Payload payload;  
   
   /**
Index: src/java/org/apache/lucene/analysis/tokenattributes/PositionIncrementAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/PositionIncrementAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/PositionIncrementAttribute.java	(working copy)
@@ -53,7 +53,7 @@
  * 
  * @see org.apache.lucene.index.TermPositions
  */
-public class PositionIncrementAttribute extends Attribute implements Cloneable, Serializable {
+public class PositionIncrementAttribute extends TokenAttribute implements Cloneable, Serializable {
   private int positionIncrement = 1;
   
   /** Set the position increment. The default value is one.
Index: src/java/org/apache/lucene/analysis/tokenattributes/TermAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/TermAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/TermAttribute.java	(working copy)
@@ -30,7 +30,7 @@
  * The APIs introduced in these classes with Lucene 2.9 might change in the future. 
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
  */
-public class TermAttribute extends Attribute implements Cloneable, Serializable {
+public class TermAttribute extends TokenAttribute implements Cloneable, Serializable {
   private static int MIN_BUFFER_SIZE = 10;
   
   private char[] termBuffer;
Index: src/java/org/apache/lucene/analysis/tokenattributes/TokenAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/TokenAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/analysis/tokenattributes/TokenAttribute.java	(revision 0)
@@ -0,0 +1,31 @@
+package org.apache.lucene.analysis.tokenattributes;
+
+import org.apache.lucene.util.Attribute;
+
+public abstract class TokenAttribute extends Attribute {
+  /**
+   * Clears the values in this Attribute and resets it to its 
+   * default value.
+   */
+  public abstract void clear();
+  
+  /**
+   * Subclasses must implement this method and should follow a syntax
+   * similar to this one:
+   * 
+   * <pre>
+   *   public String toString() {
+   *     return "start=" + startOffset + ",end=" + endOffset;
+   *   }
+   * </pre>
+   */
+  public abstract String toString();
+    
+  /**
+   * Copies the values from this Attribute into the passed-in
+   * target attribute. The type of the target must match the type
+   * of this attribute. 
+   */
+  public abstract void copyTo(Attribute target);
+
+}
Index: src/java/org/apache/lucene/analysis/tokenattributes/TokenAttributeSource.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/TokenAttributeSource.java	(revision 0)
+++ src/java/org/apache/lucene/analysis/tokenattributes/TokenAttributeSource.java	(revision 0)
@@ -0,0 +1,102 @@
+package org.apache.lucene.analysis.tokenattributes;
+
+import java.util.Iterator;
+
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.util.Attribute;
+import org.apache.lucene.util.AttributeContainer;
+import org.apache.lucene.util.AttributeSource;
+
+public class TokenAttributeSource extends AttributeContainer<TokenAttribute> {
+  /**
+   * An AttributeAcceptor defines only a single method {@link #accept(Class)}.
+   * It can be used for e. g. buffering purposes to specify which attributes
+   * to buffer. 
+   */
+  public static abstract class AttributeAcceptor {
+    /** Return true, to accept this attribute; false otherwise */
+    public abstract boolean accept(Class<? extends TokenAttribute> attClass);
+  }
+  
+  /**
+   * Default AttributeAcceptor that accepts all attributes.
+   */
+  public static final AttributeAcceptor AllAcceptor = new AttributeAcceptor() {
+    public boolean accept(Class<? extends TokenAttribute> attClass) {return true;}      
+  };
+
+  public TokenAttributeSource() {
+    super();
+  }
+  
+  public TokenAttributeSource(TokenAttributeSource input) {
+    super(input);
+  }
+  
+  /**
+   * Resets all Attributes in this AttributeSource by calling
+   * {@link Attribute#clear()} on each Attribute.
+   */
+  public void clearAttributes() {
+    Iterator<TokenAttribute> it = getAttributesIterator();
+    while (it.hasNext()) {
+      it.next().clear();
+    }
+  }
+
+  /**
+   * Restores this state by copying the values of all attributes 
+   * that this state contains into the attributes of the targetStream.
+   * The targetStream must contain a corresponding instance for each argument
+   * contained in this state.
+   * <p>
+   * Note that this method does not affect attributes of the targetStream
+   * that are not contained in this state. In other words, if for example
+   * the targetStream contains an OffsetAttribute, but this state doesn't, then
+   * the value of the OffsetAttribute remains unchanged. It might be desirable to
+   * reset its value to the default, in which case the caller should first
+   * call {@link TokenStream#clearAttributes()} on the targetStream.   
+   */
+  public void restoreState(TokenStream target) {
+    Iterator<TokenAttribute> it = getAttributesIterator();
+    while (it.hasNext()) {
+      TokenAttribute att = it.next();
+      TokenAttribute targetAtt = target.getAttribute(att.getClass());
+      att.copyTo(targetAtt);
+    }
+  }
+  
+  /**
+   * Captures the current state of the passed in TokenStream.
+   * <p>
+   * This state will contain all of the passed in TokenStream's
+   * {@link Attribute}s. If only a subset of the attributes is needed
+   * please use {@link #captureState(AttributeAcceptor)} 
+   */
+  public TokenAttributeSource captureState() {
+    return captureState(AllAcceptor);
+  }
+
+  /**
+   * Captures the current state of the passed in TokenStream.
+   * <p>
+   * This state will contain all of the passed in TokenStream's
+   * {@link Attribute}s which the {@link AttributeAcceptor} accepts. 
+   */
+  public TokenAttributeSource captureState(AttributeAcceptor acceptor) {
+    TokenAttributeSource state = new TokenAttributeSource();
+     
+    Iterator<TokenAttribute> it = getAttributesIterator();
+    while(it.hasNext()) {
+      TokenAttribute att = it.next();
+      if (acceptor.accept(att.getClass())) {
+        TokenAttribute clone = (TokenAttribute) att.clone();
+        state.attributes.put(att.getClass(), clone);
+      }
+    }
+    
+    return state;
+  }
+
+
+}
Index: src/java/org/apache/lucene/analysis/tokenattributes/TypeAttribute.java
===================================================================
--- src/java/org/apache/lucene/analysis/tokenattributes/TypeAttribute.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/tokenattributes/TypeAttribute.java	(working copy)
@@ -29,7 +29,7 @@
  * The APIs introduced in these classes with Lucene 2.9 might change in the future. 
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
  */
-public class TypeAttribute extends Attribute implements Cloneable, Serializable {
+public class TypeAttribute extends TokenAttribute implements Cloneable, Serializable {
   private String type;
   public static final String DEFAULT_TYPE = "word";
   
Index: src/java/org/apache/lucene/analysis/CachingTokenFilter.java
===================================================================
--- src/java/org/apache/lucene/analysis/CachingTokenFilter.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/CachingTokenFilter.java	(working copy)
@@ -22,6 +22,7 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.lucene.analysis.tokenattributes.TokenAttributeSource;
 import org.apache.lucene.util.AttributeSource;
 
 /**
@@ -55,7 +56,7 @@
       return false;
     }
     // Since the TokenFilter can be reset, the tokens need to be preserved as immutable.
-    AttributeSource state = (AttributeSource) iterator.next();
+    TokenAttributeSource state = (TokenAttributeSource) iterator.next();
     state.restoreState(this);
     return true;
   }
Index: src/java/org/apache/lucene/analysis/SinkTokenizer.java
===================================================================
--- src/java/org/apache/lucene/analysis/SinkTokenizer.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/SinkTokenizer.java	(working copy)
@@ -22,6 +22,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.lucene.analysis.tokenattributes.TokenAttributeSource;
 import org.apache.lucene.util.AttributeSource;
 
 
@@ -71,7 +72,7 @@
     if (iter == null) iter = lst.iterator();
     // Since this TokenStream can be reset we have to maintain the tokens as immutable
     if (iter.hasNext()) {
-      AttributeSource state = (AttributeSource) iter.next();
+      TokenAttributeSource state = (TokenAttributeSource) iter.next();
       state.restoreState(this);
       return true;
     }
Index: src/java/org/apache/lucene/analysis/TeeTokenFilter.java
===================================================================
--- src/java/org/apache/lucene/analysis/TeeTokenFilter.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/TeeTokenFilter.java	(working copy)
@@ -20,7 +20,9 @@
 import java.io.IOException;
 import java.util.Iterator;
 
+import org.apache.lucene.analysis.tokenattributes.TokenAttribute;
 
+
 /**
  * Works in conjunction with the SinkTokenizer to provide the ability to set aside tokens
  * that have already been analyzed.  This is useful in situations where multiple fields share
@@ -61,7 +63,7 @@
   public TeeTokenFilter(TokenStream input, SinkTokenizer sink) {
     super(input);
     this.sink = sink;
-    Iterator it = getAttributesIterator();
+    Iterator<TokenAttribute> it = getAttributesIterator();
     while (it.hasNext()) {
       sink.addAttribute(it.next().getClass());
     }
Index: src/java/org/apache/lucene/analysis/TokenStream.java
===================================================================
--- src/java/org/apache/lucene/analysis/TokenStream.java	(revision 754502)
+++ src/java/org/apache/lucene/analysis/TokenStream.java	(working copy)
@@ -20,6 +20,8 @@
 import java.io.IOException;
 import java.util.Iterator;
 
+import org.apache.lucene.analysis.tokenattributes.TokenAttribute;
+import org.apache.lucene.analysis.tokenattributes.TokenAttributeSource;
 import org.apache.lucene.index.Payload;
 import org.apache.lucene.util.Attribute;
 import org.apache.lucene.util.AttributeSource;
@@ -79,7 +81,7 @@
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
   */
 
-public abstract class TokenStream extends AttributeSource {
+public abstract class TokenStream extends TokenAttributeSource {
   private static boolean useNewAPIDefault = false;
   private boolean useNewAPI = useNewAPIDefault;
   
@@ -87,10 +89,10 @@
     super();
   }
   
-  protected TokenStream(AttributeSource input) {
+  protected TokenStream(TokenAttributeSource input) {
     super(input);
   }
-
+  
   /**
    * Returns whether or not the new TokenStream APIs are used
    * by default. 
Index: src/java/org/apache/lucene/index/FieldInvertState.java
===================================================================
--- src/java/org/apache/lucene/index/FieldInvertState.java	(revision 754502)
+++ src/java/org/apache/lucene/index/FieldInvertState.java	(working copy)
@@ -16,7 +16,7 @@
  */
 package org.apache.lucene.index;
 
-import org.apache.lucene.search.Similarity;
+import org.apache.lucene.util.AttributeContainer;
 import org.apache.lucene.util.AttributeSource;
 
 /**
@@ -33,7 +33,7 @@
   int numOverlap;
   int offset;
   float boost;
-  AttributeSource attributeSource;
+  AttributeContainer attributeSource;
 
   public FieldInvertState() {
   }
Index: src/java/org/apache/lucene/newdoc/demo/ByteFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/ByteFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/ByteFieldValue.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.apache.lucene.newdoc.demo;
+
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+
+public class ByteFieldValue extends FieldValue {
+
+}
Index: src/java/org/apache/lucene/newdoc/demo/Codec.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/Codec.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/Codec.java	(revision 0)
@@ -0,0 +1,9 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.io.PrintStream;
+
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+
+public abstract class Codec <T extends FieldValue> {
+  abstract void encode(T value, PrintStream stream);
+}
Index: src/java/org/apache/lucene/newdoc/demo/DateCodec.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/DateCodec.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/DateCodec.java	(revision 0)
@@ -0,0 +1,17 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+
+import org.apache.lucene.newdoc.fieldvalues.DateFieldValue;
+
+public class DateCodec extends Codec<DateFieldValue> {
+  private SimpleDateFormat dateformatter = new SimpleDateFormat();
+  
+  
+  @Override
+  void encode(DateFieldValue value, PrintStream stream) {
+    stream.print(dateformatter.format(value.getDate()));
+  }
+
+}
Index: src/java/org/apache/lucene/newdoc/demo/DocumentConsumer.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/DocumentConsumer.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/DocumentConsumer.java	(revision 0)
@@ -0,0 +1,163 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.lucene.newdoc.Document;
+import org.apache.lucene.newdoc.DocumentDescriptor;
+import org.apache.lucene.newdoc.FieldDescriptor;
+import org.apache.lucene.newdoc.Document.VariableField;
+import org.apache.lucene.newdoc.fieldattributes.NumericFieldAttribute;
+import org.apache.lucene.newdoc.fieldattributes.StoreAttribute;
+import org.apache.lucene.newdoc.fieldvalues.DateFieldValue;
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+import org.apache.lucene.newdoc.fieldvalues.IntFieldValue;
+import org.apache.lucene.newdoc.fieldvalues.MultiFieldValue;
+import org.apache.lucene.newdoc.fieldvalues.StringFieldValue;
+
+public class DocumentConsumer {
+  
+  private abstract static class Consumer {
+    protected List<Integer> fixedFieldIds = new ArrayList<Integer>();
+    
+    void init(DocumentDescriptor descriptor) {
+      int id = 0;
+      Iterator<FieldDescriptor<? extends FieldValue>> it = descriptor.getFieldIterator();
+      while(it.hasNext()) {
+        FieldDescriptor<? extends FieldValue> fd = it.next();
+        if (useField(fd)) {
+          fixedFieldIds.add(id);
+        }
+        id++;
+      }
+    }
+    
+    public void consumeDocument(Document doc) {
+      consumeFixedFields(doc);
+      if (doc.hasVariableFields()) {
+        consumeVariableFields(doc);
+      }
+    }
+    
+    <T extends FieldValue> void writeField(FieldValue fv) {
+      if (fv instanceof MultiFieldValue<?>) {
+        Iterator<T> it =(Iterator<T>)  ((MultiFieldValue<?>) fv).getValuesIterator();
+        while (it.hasNext()) {
+          writeField(it.next());
+        }
+        return;
+      }
+    }
+    
+    void consumeFixedFields(Document doc) {
+      for (int id : this.fixedFieldIds) {
+        FieldValue fv = doc.getFieldValue(id);
+        writeField(fv);
+      }  
+    }
+    
+    void consumeVariableFields(Document doc) {
+      Iterator<VariableField<? extends FieldValue>> it = doc.getVariableFieldsIterator();
+      
+      while (it.hasNext()) {
+        VariableField<? extends FieldValue> vf = it.next();
+        FieldDescriptor<? extends FieldValue> fd = vf.getDescriptor();
+        if (useField(fd)) {
+          writeField(vf.getValue());
+        }
+      }
+    }
+    
+    abstract <T extends FieldValue> boolean useField(FieldDescriptor<? extends FieldValue> fd);
+  }
+  
+  private class StoredFieldsWriter extends Consumer {
+    StringCodec sc = new StringCodec();
+    DateCodec dc = new DateCodec();
+    
+    public void consumeDocument(Document doc) {
+      System.out.print("Stored fields: ");
+      super.consumeDocument(doc);
+    }
+    
+    <T extends FieldValue> boolean useField(FieldDescriptor<? extends FieldValue> fd) {
+      if (fd.hasAttribute(StoreAttribute.class)) {
+        StoreAttribute store = fd.getAttribute(StoreAttribute.class);
+        return store.isStore();
+      }
+      
+      return false;
+    }
+    
+    <T extends FieldValue> void writeField(FieldValue fv) {
+      super.writeField(fv);
+      
+      if (fv instanceof StringFieldValue) {
+        sc.encode((StringFieldValue) fv, System.out);
+        System.out.print(", ");
+      } else if (fv instanceof DateFieldValue) {
+        dc.encode((DateFieldValue) fv, System.out);
+        System.out.print(", ");
+      }  
+    }
+    
+  }
+
+  private class TrieFieldsWriter extends Consumer {
+    TrieEncoder encoder = new TrieEncoder();
+    
+    public void consumeDocument(Document doc) {
+      System.out.print("Trie fields: ");
+      super.consumeDocument(doc);
+    }
+    
+    <T extends FieldValue> boolean useField(FieldDescriptor<? extends FieldValue> fd) {
+      if (fd.hasAttribute(NumericFieldAttribute.class)) {
+        NumericFieldAttribute nf = fd.getAttribute(NumericFieldAttribute.class);
+        return nf.isIndexAsTrie();
+      }
+      
+      return false;
+    }
+    
+    <T extends FieldValue> void writeField(FieldValue fv) {
+      super.writeField(fv);
+      
+      if (fv instanceof IntFieldValue) {
+        encoder.encode(((IntFieldValue) fv).getValue(), System.out);
+        System.out.print(", ");
+      }
+
+      if (fv instanceof DateFieldValue) {
+        encoder.encode(((DateFieldValue) fv).getDate().getTime(), System.out);
+        System.out.print(", ");
+      }
+  
+    }
+    
+  }
+
+  
+  List<Consumer> consumers = new LinkedList<Consumer>();
+  
+  public DocumentConsumer(DocumentDescriptor descriptor) {
+    StoredFieldsWriter storedFieldsWriter = new StoredFieldsWriter();
+    storedFieldsWriter.init(descriptor);
+    this.consumers.add(storedFieldsWriter);
+
+    TrieFieldsWriter trieFieldsWriter = new TrieFieldsWriter();
+    trieFieldsWriter.init(descriptor);
+    this.consumers.add(trieFieldsWriter);
+
+    
+  }
+  
+  public void addDocument(Document doc) {
+    for (Consumer c : this.consumers) {
+      c.consumeDocument(doc);
+    }
+    System.out.println();
+  }
+}
Index: src/java/org/apache/lucene/newdoc/demo/DocumentProducer.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/DocumentProducer.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/DocumentProducer.java	(revision 0)
@@ -0,0 +1,68 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.util.Date;
+
+import org.apache.lucene.newdoc.DocumentDescriptor;
+import org.apache.lucene.newdoc.Document;
+import org.apache.lucene.newdoc.FieldDescriptor;
+import org.apache.lucene.newdoc.fieldattributes.IndexAttribute;
+import org.apache.lucene.newdoc.fieldattributes.StoreAttribute;
+import org.apache.lucene.newdoc.fieldattributes.TermVectorAttribute;
+import org.apache.lucene.newdoc.fieldvalues.DateFieldValue;
+import org.apache.lucene.newdoc.fieldvalues.IntFieldValue;
+import org.apache.lucene.newdoc.fieldvalues.StringFieldValue;
+
+public class DocumentProducer {
+  public static void main(String[] args) throws Exception {
+    DocumentDescriptor documentDescriptor = new DocumentDescriptor();
+    StoreAttribute.DefaultStore = true;
+    
+    // add a few fields
+    FieldDescriptor<IntFieldValue> countField = FieldDescriptor.newInstance("count", IntFieldValue.class, false);
+    documentDescriptor.addFieldDescriptor(countField);
+    
+    FieldDescriptor<StringFieldValue> authorField = FieldDescriptor.newInstance("author", StringFieldValue.class, true);
+    
+    IndexAttribute index = authorField.getAttribute(IndexAttribute.class);
+    index.setAnalyzed(false);
+    index.setOmitNorms(true);
+    documentDescriptor.addFieldDescriptor(authorField);
+
+    FieldDescriptor<DateFieldValue> dateField = FieldDescriptor.newInstance("date", DateFieldValue.class, false);
+    documentDescriptor.addFieldDescriptor(dateField);
+
+    FieldDescriptor<StringFieldValue> contentField = FieldDescriptor.newInstance("content", StringFieldValue.class, false);
+    index = contentField.getAttribute(IndexAttribute.class);
+    index.setAnalyzed(true);
+    index.setOmitNorms(false);
+    TermVectorAttribute vector = contentField.getAttribute(TermVectorAttribute.class);
+    vector.setStoreOffsets(false);
+    vector.setStorePositions(true);
+    documentDescriptor.addFieldDescriptor(contentField);
+    
+    
+    // now index actual documents
+    
+    DocumentConsumer indexWriter = new DocumentConsumer(documentDescriptor);
+    for (int i = 0; i < 10; i++) {
+      Document doc = new Document(documentDescriptor);
+      doc.addFieldValue(countField, new IntFieldValue(50));
+      doc.addFieldValue(authorField, new StringFieldValue("author " + i));
+      doc.addFieldValue(authorField, new StringFieldValue("coauthor " + i));
+      doc.addFieldValue(dateField, new DateFieldValue(new Date()));
+      // this would not compile 
+      //doc.setFieldValue(authorField, new ByteFieldValue());
+      
+      doc.addFieldValue(contentField, new StringFieldValue("This is a new document API - " + i));
+      
+      if (i % 2 == 0) {
+        FieldDescriptor<StringFieldValue> varFd = FieldDescriptor.newInstance("varfield", StringFieldValue.class, true);
+        doc.addVariableField(varFd);
+        doc.addFieldValue(varFd, new StringFieldValue("every other doc has this field"));
+        doc.addFieldValue(varFd, new StringFieldValue("and this one too!"));
+      }
+      
+      indexWriter.addDocument(doc);
+    }
+  }
+}
Index: src/java/org/apache/lucene/newdoc/demo/StringCodec.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/StringCodec.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/StringCodec.java	(revision 0)
@@ -0,0 +1,16 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.io.PrintStream;
+
+import org.apache.lucene.newdoc.fieldvalues.StringFieldValue;
+
+
+public class StringCodec extends Codec<StringFieldValue> {
+
+  @Override
+  void encode(StringFieldValue value, PrintStream stream) {
+    stream.print(value.getValue());
+  }
+
+  
+}
Index: src/java/org/apache/lucene/newdoc/demo/TrieEncoder.java
===================================================================
--- src/java/org/apache/lucene/newdoc/demo/TrieEncoder.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/demo/TrieEncoder.java	(revision 0)
@@ -0,0 +1,14 @@
+package org.apache.lucene.newdoc.demo;
+
+import java.io.PrintStream;
+
+public class TrieEncoder {
+  public void encode(int value, PrintStream out) {
+    out.print("int=" + value );
+  }
+
+  public void encode(long value, PrintStream out) {
+    out.print("long=" + value);
+  }
+
+}
Index: src/java/org/apache/lucene/newdoc/fieldattributes/FieldAttribute.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldattributes/FieldAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldattributes/FieldAttribute.java	(revision 0)
@@ -0,0 +1,6 @@
+package org.apache.lucene.newdoc.fieldattributes;
+
+import org.apache.lucene.util.Attribute;
+
+public abstract class FieldAttribute extends Attribute {
+}
Index: src/java/org/apache/lucene/newdoc/fieldattributes/IndexAttribute.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldattributes/IndexAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldattributes/IndexAttribute.java	(revision 0)
@@ -0,0 +1,56 @@
+package org.apache.lucene.newdoc.fieldattributes;
+
+public class IndexAttribute extends FieldAttribute {
+  public static boolean DefaultIndexed = true; 
+  public static boolean DefaultAnalyzed = true;
+  public static boolean DefaultOmitNorms = false;
+  
+  private boolean indexed = DefaultIndexed;
+  private boolean analyzed = DefaultAnalyzed;
+  private boolean omitNorms = DefaultOmitNorms;
+  
+  
+  
+  @Override
+  public String toString() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+
+
+  public boolean isAnalyzed() {
+    return analyzed;
+  }
+
+
+
+  public void setAnalyzed(boolean analyzed) {
+    this.analyzed = analyzed;
+  }
+
+
+
+  public boolean isOmitNorms() {
+    return omitNorms;
+  }
+
+
+
+  public void setOmitNorms(boolean omitNorms) {
+    this.omitNorms = omitNorms;
+  }
+
+
+
+  public void setIndexed(boolean indexed) {
+    this.indexed = indexed;
+  }
+
+
+
+  public boolean isIndexed() {
+    return indexed;
+  }
+
+}
Index: src/java/org/apache/lucene/newdoc/fieldattributes/NumericFieldAttribute.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldattributes/NumericFieldAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldattributes/NumericFieldAttribute.java	(revision 0)
@@ -0,0 +1,36 @@
+package org.apache.lucene.newdoc.fieldattributes;
+
+public class NumericFieldAttribute extends FieldAttribute {
+  public static boolean DefaultIndexAsTrie = true;
+  public static boolean DefaultZeroPadding = false;
+  
+  private boolean zeroPadding = DefaultZeroPadding;
+  private boolean indexAsTrie = DefaultIndexAsTrie;
+  
+  
+  @Override
+  public String toString() {
+    return null;
+  }
+
+
+  public boolean isZeroPadding() {
+    return zeroPadding;
+  }
+
+
+  public void setZeroPadding(boolean zeroPadding) {
+    this.zeroPadding = zeroPadding;
+  }
+
+
+  public boolean isIndexAsTrie() {
+    return indexAsTrie;
+  }
+
+
+  public void setIndexAsTrie(boolean indexAsTrie) {
+    this.indexAsTrie = indexAsTrie;
+  }
+
+}
Index: src/java/org/apache/lucene/newdoc/fieldattributes/StoreAttribute.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldattributes/StoreAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldattributes/StoreAttribute.java	(revision 0)
@@ -0,0 +1,36 @@
+package org.apache.lucene.newdoc.fieldattributes;
+
+public class StoreAttribute extends FieldAttribute {
+  public static boolean DefaultStore = false;
+  public static boolean DefaultCompress = false;
+  
+  private boolean store = DefaultStore;
+  private boolean compress = DefaultCompress;
+  
+  @Override
+  public String toString() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+
+  public boolean isCompress() {
+    return compress;
+  }
+
+
+  public void setCompress(boolean compress) {
+    this.compress = compress;
+  }
+
+
+  public void setStore(boolean store) {
+    this.store = store;
+  }
+
+
+  public boolean isStore() {
+    return store;
+  }
+
+}
Index: src/java/org/apache/lucene/newdoc/fieldattributes/TermVectorAttribute.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldattributes/TermVectorAttribute.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldattributes/TermVectorAttribute.java	(revision 0)
@@ -0,0 +1,51 @@
+package org.apache.lucene.newdoc.fieldattributes;
+
+public class TermVectorAttribute extends FieldAttribute {
+  public static boolean DefaultStoreTermVectors = false;
+  public static boolean DefaultStorePositions = false;
+  public static boolean DefaultStoreOffsets = false;
+  
+  private boolean storeTermVectors = DefaultStoreTermVectors;
+  private boolean storePositions = DefaultStorePositions;
+  private boolean storeOffsets = DefaultStoreOffsets;
+  
+  
+  @Override
+  public String toString() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+
+  public boolean isStorePositions() {
+    return storePositions;
+  }
+
+
+  public void setStorePositions(boolean storePositions) {
+    this.storePositions = storePositions;
+  }
+
+
+  public boolean isStoreOffsets() {
+    return storeOffsets;
+  }
+
+
+  public void setStoreOffsets(boolean storeOffsets) {
+    this.storeOffsets = storeOffsets;
+  }
+
+
+  public void setStoreTermVectors(boolean storeTermVectors) {
+    this.storeTermVectors = storeTermVectors;
+  }
+
+
+  public boolean isStoreTermVectors() {
+    return storeTermVectors;
+  }
+  
+  
+
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/DateFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/DateFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/DateFieldValue.java	(revision 0)
@@ -0,0 +1,23 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import java.util.Date;
+
+import org.apache.lucene.newdoc.fieldattributes.NumericFieldAttribute;
+
+@UseFieldAttributes(NumericFieldAttribute.class)
+public class DateFieldValue extends FieldValue {
+  private Date date;
+
+  public DateFieldValue(Date date) {
+    super();
+    this.date = date;
+  }
+
+  public Date getDate() {
+    return date;
+  }
+
+  public void setDate(Date date) {
+    this.date = date;
+  }
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/FieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/FieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/FieldValue.java	(revision 0)
@@ -0,0 +1,10 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import org.apache.lucene.newdoc.fieldattributes.IndexAttribute;
+import org.apache.lucene.newdoc.fieldattributes.StoreAttribute;
+import org.apache.lucene.newdoc.fieldattributes.TermVectorAttribute;
+
+@UseFieldAttributes({StoreAttribute.class, IndexAttribute.class, TermVectorAttribute.class})
+public abstract class FieldValue {
+  
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/IntFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/IntFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/IntFieldValue.java	(revision 0)
@@ -0,0 +1,20 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import org.apache.lucene.newdoc.fieldattributes.NumericFieldAttribute;
+
+@UseFieldAttributes(NumericFieldAttribute.class)
+public class IntFieldValue extends FieldValue {
+  private int value;
+  
+  public IntFieldValue(int value) {
+    this.value = value;
+  }
+
+  public void setValue(int value) {
+    this.value = value;
+  }
+
+  public int getValue() {
+    return value;
+  }
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/MultiFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/MultiFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/MultiFieldValue.java	(revision 0)
@@ -0,0 +1,28 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class MultiFieldValue<T extends FieldValue> extends FieldValue {
+  private List<T> values;
+  
+  public MultiFieldValue(T value) {
+    addValue(value);
+  }
+  
+  public void addValue(T value) {
+    if (values == null) {
+      values = new LinkedList<T>();
+    }
+    values.add(value);
+  }
+  
+  public int getNumValues() {
+    return (values == null) ? 0 : values.size();
+  }
+  
+  public Iterator<T> getValuesIterator() {
+    return values.iterator();
+  }
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/ReaderFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/ReaderFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/ReaderFieldValue.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import java.io.Reader;
+
+public class ReaderFieldValue {
+  private Reader reader;
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/StringFieldValue.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/StringFieldValue.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/StringFieldValue.java	(revision 0)
@@ -0,0 +1,19 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+
+public class StringFieldValue extends FieldValue {
+  private String value;
+
+  public StringFieldValue(String value) {
+    this.value = value;
+  }
+  
+  public String getValue() {
+    return value;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+  
+}
Index: src/java/org/apache/lucene/newdoc/fieldvalues/UseFieldAttributes.java
===================================================================
--- src/java/org/apache/lucene/newdoc/fieldvalues/UseFieldAttributes.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/fieldvalues/UseFieldAttributes.java	(revision 0)
@@ -0,0 +1,14 @@
+package org.apache.lucene.newdoc.fieldvalues;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.lucene.newdoc.fieldattributes.FieldAttribute;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UseFieldAttributes {
+  Class<? extends FieldAttribute>[] value();
+}
Index: src/java/org/apache/lucene/newdoc/Document.java
===================================================================
--- src/java/org/apache/lucene/newdoc/Document.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/Document.java	(revision 0)
@@ -0,0 +1,109 @@
+package org.apache.lucene.newdoc;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+import org.apache.lucene.newdoc.fieldvalues.MultiFieldValue;
+
+public class Document {
+  private DocumentDescriptor descriptor;
+  
+  public static class VariableField<T extends FieldValue> {
+    private FieldDescriptor<? extends FieldValue> descriptor;
+    private FieldValue      value;
+    
+    VariableField(FieldDescriptor<T> descriptor, T value) {
+      this.descriptor = descriptor;
+      this.value = value;
+    }
+
+    public FieldDescriptor<? extends FieldValue> getDescriptor() {
+      return descriptor;
+    }
+
+    public FieldValue getValue() {
+      return value;
+    }
+  }
+  
+  private FieldValue[]               fixedFields;
+  private Map<String, VariableField<? extends FieldValue>> variableFields;
+  
+  public Document(DocumentDescriptor descriptor) {
+    this.descriptor = descriptor;
+    this.fixedFields = new FieldValue[descriptor.getNumberOfFields()];
+  }
+
+  public <T extends FieldValue> void addFieldValue(String fieldName, T value) {
+    FieldDescriptor<T> fieldDescriptor = (FieldDescriptor<T>) descriptor.getFieldDescriptor(fieldName);
+    addFieldValue(fieldDescriptor, value);
+  }
+  
+  public <T extends FieldValue> void addFieldValue(FieldDescriptor<T> fieldDescriptor, T value) {
+    int id = this.descriptor.getFieldId(fieldDescriptor.getFieldName());
+
+    if (id != -1) {
+      if (fixedFields[id] == null) {
+        if (fieldDescriptor.allowsMultipleValues()) {
+          fixedFields[id] = new MultiFieldValue<T>(value);
+        } else {
+          fixedFields[id] = value;
+        }
+      } else {
+        if (fieldDescriptor.allowsMultipleValues()) {
+          ((MultiFieldValue<T>) fixedFields[id]).addValue(value);
+        } else {
+          throw new IllegalArgumentException("This field does not support multiple values.");
+        }
+      }
+    } else {
+      VariableField vf = this.variableFields.get(fieldDescriptor.getFieldName());
+      if (vf == null) {
+        throw new IllegalArgumentException("No field descriptor with name '" + fieldDescriptor.getFieldName() + "' found.");
+      }
+      
+      if (vf.value == null) {
+        if (fieldDescriptor.allowsMultipleValues()) {
+          vf.value = new MultiFieldValue<T>(value);
+        } else {
+          vf.value = value;
+        }
+      } else {
+        if (fieldDescriptor.allowsMultipleValues()) {
+          ((MultiFieldValue<T>) vf.value).addValue(value);
+        } else {
+          throw new IllegalArgumentException("This field does not support multiple values.");
+        }
+      }
+      
+    }
+    
+    
+  }
+  
+  public <T extends FieldValue> void addVariableField(FieldDescriptor<T> descriptor) {
+    if (this.variableFields == null) {
+      this.variableFields = new HashMap<String, VariableField<? extends FieldValue>>();
+    }
+    this.variableFields.put(descriptor.getFieldName(), new VariableField<T>(descriptor, null));
+  }
+  
+  public boolean hasVariableFields() {
+    return this.variableFields != null && this.variableFields.size() > 0;
+  }
+  
+  public Iterator<VariableField<? extends FieldValue>> getVariableFieldsIterator() {
+    if (this.variableFields == null) {
+      return null;
+    }
+    return this.variableFields.values().iterator();
+  }
+  
+  public FieldValue getFieldValue(int id) {
+    return this.fixedFields[id];
+  }
+}
Index: src/java/org/apache/lucene/newdoc/DocumentDescriptor.java
===================================================================
--- src/java/org/apache/lucene/newdoc/DocumentDescriptor.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/DocumentDescriptor.java	(revision 0)
@@ -0,0 +1,42 @@
+package org.apache.lucene.newdoc;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+
+public class DocumentDescriptor {
+  private Map<String, FieldDescriptor<? extends FieldValue>> fields;
+  private Map<String, Integer> fieldIds;
+  
+  private int idCounter;
+  
+  public DocumentDescriptor() {
+    this.fields = new LinkedHashMap<String, FieldDescriptor<? extends FieldValue>>();
+    this.fieldIds = new LinkedHashMap<String, Integer>();
+    this.idCounter = 0;
+  }
+
+  public void addFieldDescriptor(FieldDescriptor<? extends FieldValue> fieldDescriptor) {
+    this.fields.put(fieldDescriptor.getFieldName(), fieldDescriptor);
+    this.fieldIds.put(fieldDescriptor.getFieldName(), this.idCounter++);
+  }
+  
+  public int getNumberOfFields() {
+    return this.fields.size();
+  }
+  
+  public int getFieldId(String field) {
+    Integer id = this.fieldIds.get(field);
+    return (id != null) ? id : -1;
+  }
+  
+  public FieldDescriptor<? extends FieldValue> getFieldDescriptor(String fieldName) {
+    return this.fields.get(fieldName);
+  }
+  
+  public Iterator<FieldDescriptor<? extends FieldValue>> getFieldIterator() {
+    return this.fields.values().iterator();
+  }
+}
Index: src/java/org/apache/lucene/newdoc/FieldDescriptor.java
===================================================================
--- src/java/org/apache/lucene/newdoc/FieldDescriptor.java	(revision 0)
+++ src/java/org/apache/lucene/newdoc/FieldDescriptor.java	(revision 0)
@@ -0,0 +1,53 @@
+package org.apache.lucene.newdoc;
+
+import org.apache.lucene.newdoc.fieldattributes.FieldAttribute;
+import org.apache.lucene.newdoc.fieldvalues.FieldValue;
+import org.apache.lucene.newdoc.fieldvalues.UseFieldAttributes;
+import org.apache.lucene.util.AttributeContainer;
+import org.apache.lucene.util.AttributeSource;
+
+
+public class FieldDescriptor <T extends FieldValue> extends AttributeSource<FieldAttribute> {
+  public static <Type extends FieldValue> FieldDescriptor<Type> newInstance(String name, Class<Type> valueType, boolean multiValue) {
+    FieldDescriptor<Type> fd = new FieldDescriptor<Type>(name, valueType, multiValue);
+    
+    Class<?> classToReflect = valueType;
+    do {
+      if (classToReflect.isAnnotationPresent(UseFieldAttributes.class)) {
+        UseFieldAttributes attribute = classToReflect.getAnnotation(UseFieldAttributes.class);
+        Class<? extends FieldAttribute>[] value = attribute.value();
+        for (Class<? extends FieldAttribute> fa : value) {
+          fd.fieldAttributes.addAttribute(fa);
+        }
+
+      }
+      
+      classToReflect = classToReflect.getSuperclass();
+    } while (classToReflect != null);
+    return fd;
+  }
+  
+  private AttributeContainer<FieldAttribute> fieldAttributes;
+  private String fieldName;
+  private Class<T> valueType;
+  private boolean multipleValuesAllowed;
+  
+  private FieldDescriptor(String fieldName, Class<T> valueType, boolean multiValue) {
+    this.fieldName = fieldName;
+    this.valueType = valueType;
+    this.fieldAttributes = new AttributeContainer<FieldAttribute>(this);
+    this.multipleValuesAllowed = multiValue;
+  }
+  
+  public String getFieldName() {
+    return this.fieldName;
+  }
+  
+  public Class<T> getValueType() {
+    return this.valueType;
+  }
+  
+  public boolean allowsMultipleValues() {
+    return this.multipleValuesAllowed;
+  }
+}
Index: src/java/org/apache/lucene/util/Attribute.java
===================================================================
--- src/java/org/apache/lucene/util/Attribute.java	(revision 754502)
+++ src/java/org/apache/lucene/util/Attribute.java	(working copy)
@@ -32,12 +32,6 @@
  */
 public abstract class Attribute implements Cloneable, Serializable {  
   /**
-   * Clears the values in this Attribute and resets it to its 
-   * default value.
-   */
-  public abstract void clear();
-  
-  /**
    * Subclasses must implement this method and should follow a syntax
    * similar to this one:
    * 
@@ -48,36 +42,6 @@
    * </pre>
    */
   public abstract String toString();
-  
-  /**
-   * Subclasses must implement this method and should compute
-   * a hashCode similar to this:
-   * <pre>
-   *   public int hashCode() {
-   *     int code = startOffset;
-   *     code = code * 31 + endOffset;
-   *     return code;
-   *   }
-   * </pre> 
-   * 
-   * see also {@link #equals(Object)}
-   */
-  public abstract int hashCode();
-  
-  /**
-   * All values used for computation of {@link #hashCode()} 
-   * should be checked here for equality.
-   * 
-   * see also {@link Object#equals(Object)}
-   */
-  public abstract boolean equals(Object other);
-  
-  /**
-   * Copies the values from this Attribute into the passed-in
-   * target attribute. The type of the target must match the type
-   * of this attribute. 
-   */
-  public abstract void copyTo(Attribute target);
     
   /**
    * Shallow clone. Subclasses must override this if they 
Index: src/java/org/apache/lucene/util/AttributeContainer.java
===================================================================
--- src/java/org/apache/lucene/util/AttributeContainer.java	(revision 0)
+++ src/java/org/apache/lucene/util/AttributeContainer.java	(revision 0)
@@ -0,0 +1,35 @@
+package org.apache.lucene.util;
+
+import java.util.LinkedHashMap;
+
+public class AttributeContainer <AttType extends Attribute> extends AttributeSource<AttType> {
+  public AttributeContainer() {
+    this.attributes = new LinkedHashMap();
+  }
+  
+  public AttributeContainer(AttributeSource input) {
+    this.attributes = input.attributes;
+  }
+
+  public <T extends AttType> T addAttribute(Class<T> attClass) {
+    T att = (T) attributes.get(attClass);
+    if (att == null) {
+      att = createInstance(attClass);
+      attributes.put(attClass, att);
+    }
+    return att;
+  }
+  
+  protected <T> T createInstance(Class<T> attClass) {
+    T instance = null;
+    try {
+      instance = attClass.newInstance();
+    } catch (InstantiationException e) {
+      throw new IllegalArgumentException("Could not instantiate class " + attClass);
+    } catch (IllegalAccessException e) {
+      throw new IllegalArgumentException("Could not instantiate class " + attClass);      
+    }    
+    
+    return instance;
+  }
+}
Index: src/java/org/apache/lucene/util/AttributeSource.java
===================================================================
--- src/java/org/apache/lucene/util/AttributeSource.java	(revision 754502)
+++ src/java/org/apache/lucene/util/AttributeSource.java	(working copy)
@@ -38,28 +38,11 @@
  * The APIs introduced in these classes with Lucene 2.9 might change in the future. 
  * We will make our best efforts to keep the APIs backwards-compatible.</font>
  */
-public class AttributeSource {
+public class AttributeSource <AttType extends Attribute> {
   /**
-   * An AttributeAcceptor defines only a single method {@link #accept(Class)}.
-   * It can be used for e. g. buffering purposes to specify which attributes
-   * to buffer. 
-   */
-  public static abstract class AttributeAcceptor {
-    /** Return true, to accept this attribute; false otherwise */
-    public abstract boolean accept(Class attClass);
-  }
-  
-  /**
-   * Default AttributeAcceptor that accepts all attributes.
-   */
-  public static final AttributeAcceptor AllAcceptor = new AttributeAcceptor() {
-    public boolean accept(Class attClass) {return true;}      
-  };
-
-  /**
    * Holds the Class&lt;Attribute&gt; -> Attribute mapping
    */
-  protected Map attributes;
+  protected Map<Class<? extends AttType>, AttType> attributes;
 
   public AttributeSource() {
     this.attributes = new LinkedHashMap();
@@ -72,32 +55,10 @@
   /** Returns an iterator that iterates the attributes 
    * in the same order they were added in.
    */
-  public Iterator getAttributesIterator() {
+  public Iterator<AttType> getAttributesIterator() {
     return attributes.values().iterator();
   }
   
-  /**
-   * The caller must pass in a Class&lt;? extends Attribute&gt; value.
-   * This method first checks if an instance of that class is 
-   * already in this AttributeSource and returns it. Otherwise a
-   * new instance is created, added to this AttributeSource and returned. 
-   */
-  public Attribute addAttribute(Class attClass) {
-    Attribute att = (Attribute) attributes.get(attClass);
-    if (att == null) {
-      try {
-        att = (Attribute) attClass.newInstance();
-      } catch (InstantiationException e) {
-        throw new IllegalArgumentException("Could not instantiate class " + attClass);
-      } catch (IllegalAccessException e) {
-        throw new IllegalArgumentException("Could not instantiate class " + attClass);      
-      }
-      
-      attributes.put(attClass, att);
-    }
-    return att;
-  }
-  
   /** Returns true, iff this AttributeSource has any attributes */
   public boolean hasAttributes() {
     return !this.attributes.isEmpty();
@@ -107,7 +68,7 @@
    * The caller must pass in a Class&lt;? extends Attribute&gt; value. 
    * Returns true, iff this AttributeSource contains the passed-in Attribute.
    */
-  public boolean hasAttribute(Class attClass) {
+  public boolean hasAttribute(Class<? extends AttType> attClass) {
     return this.attributes.containsKey(attClass);
   }
 
@@ -118,80 +79,15 @@
    * @throws IllegalArgumentException if this AttributeSource does not contain the
    *         Attribute
    */
-  public Attribute getAttribute(Class attClass) {
-    Attribute att = (Attribute) this.attributes.get(attClass);
+  public <T extends AttType> T getAttribute(Class<T> attClass) {
+    AttType att = this.attributes.get(attClass);
     if (att == null) {
       throw new IllegalArgumentException("This token does not have the attribute '" + attClass + "'.");
     }
-
-    return att;
-  }
   
-  /**
-   * Resets all Attributes in this AttributeSource by calling
-   * {@link Attribute#clear()} on each Attribute.
-   */
-  public void clearAttributes() {
-    Iterator it = getAttributesIterator();
-    while (it.hasNext()) {
-      ((Attribute) it.next()).clear();
-    }
+    return (T) att;
   }
-  
-  /**
-   * Captures the current state of the passed in TokenStream.
-   * <p>
-   * This state will contain all of the passed in TokenStream's
-   * {@link Attribute}s. If only a subset of the attributes is needed
-   * please use {@link #captureState(AttributeAcceptor)} 
-   */
-  public AttributeSource captureState() {
-    return captureState(AllAcceptor);
-  }
-
-  /**
-   * Captures the current state of the passed in TokenStream.
-   * <p>
-   * This state will contain all of the passed in TokenStream's
-   * {@link Attribute}s which the {@link AttributeAcceptor} accepts. 
-   */
-  public AttributeSource captureState(AttributeAcceptor acceptor) {
-    AttributeSource state = new AttributeSource();
-     
-    Iterator it = getAttributesIterator();
-    while(it.hasNext()) {
-      Attribute att = (Attribute) it.next();
-      if (acceptor.accept(att.getClass())) {
-        Attribute clone = (Attribute) att.clone();
-        state.attributes.put(att.getClass(), clone);
-      }
-    }
-    
-    return state;
-  }
-  
-  /**
-   * Restores this state by copying the values of all attributes 
-   * that this state contains into the attributes of the targetStream.
-   * The targetStream must contain a corresponding instance for each argument
-   * contained in this state.
-   * <p>
-   * Note that this method does not affect attributes of the targetStream
-   * that are not contained in this state. In other words, if for example
-   * the targetStream contains an OffsetAttribute, but this state doesn't, then
-   * the value of the OffsetAttribute remains unchanged. It might be desirable to
-   * reset its value to the default, in which case the caller should first
-   * call {@link TokenStream#clearAttributes()} on the targetStream.   
-   */
-  public void restoreState(AttributeSource target) {
-    Iterator it = getAttributesIterator();
-    while (it.hasNext()) {
-      Attribute att = (Attribute) it.next();
-      Attribute targetAtt = target.getAttribute(att.getClass());
-      att.copyTo(targetAtt);
-    }
-  }
-  
+        
   public int hashCode() {
     int code = 0;
     if (hasAttributes()) {
Index: src/test/org/apache/lucene/index/TestDocumentWriter.java
===================================================================
--- src/test/org/apache/lucene/index/TestDocumentWriter.java	(revision 754502)
+++ src/test/org/apache/lucene/index/TestDocumentWriter.java	(working copy)
@@ -30,6 +30,7 @@
 import org.apache.lucene.analysis.tokenattributes.PayloadAttribute;
 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
 import org.apache.lucene.analysis.tokenattributes.TermAttribute;
+import org.apache.lucene.analysis.tokenattributes.TokenAttributeSource;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.Fieldable;
@@ -141,7 +142,7 @@
       public TokenStream tokenStream(String fieldName, Reader reader) {
         return new TokenFilter(new WhitespaceTokenizer(reader)) {
           boolean first=true;
-          AttributeSource state;
+          TokenAttributeSource state;
 
           public boolean incrementToken() throws IOException {
             if (state != null) {
Index: src/test/org/apache/lucene/index/TestIndexWriter.java
===================================================================
--- src/test/org/apache/lucene/index/TestIndexWriter.java	(revision 754502)
+++ src/test/org/apache/lucene/index/TestIndexWriter.java	(working copy)
@@ -37,6 +37,7 @@
 import org.apache.lucene.analysis.standard.StandardTokenizer;
 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
 import org.apache.lucene.analysis.tokenattributes.TermAttribute;
+import org.apache.lucene.analysis.tokenattributes.TokenAttributeSource;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.search.IndexSearcher;
@@ -3595,14 +3596,14 @@
     tokens.addAttribute(TermAttribute.class);
     tokens.addAttribute(PositionIncrementAttribute.class);
 
-    AttributeSource state = new AttributeSource();
+    TokenAttributeSource state = new TokenAttributeSource();
     TermAttribute termAtt = (TermAttribute) state.addAttribute(TermAttribute.class);
     PositionIncrementAttribute posIncrAtt = (PositionIncrementAttribute) state.addAttribute(PositionIncrementAttribute.class);
     termAtt.setTermBuffer("a");
     posIncrAtt.setPositionIncrement(0);
     tokens.add(state);
 
-    state = new AttributeSource();
+    state = new TokenAttributeSource();
     termAtt = (TermAttribute) state.addAttribute(TermAttribute.class);
     posIncrAtt = (PositionIncrementAttribute) state.addAttribute(PositionIncrementAttribute.class);
 
@@ -3610,7 +3611,7 @@
     posIncrAtt.setPositionIncrement(1);
     tokens.add(state);
     
-    state = new AttributeSource();
+    state = new TokenAttributeSource();
     termAtt = (TermAttribute) state.addAttribute(TermAttribute.class);
     posIncrAtt = (PositionIncrementAttribute) state.addAttribute(PositionIncrementAttribute.class);
 
