Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 922585) +++ CHANGES.txt (working copy) @@ -167,6 +167,11 @@ * LUCENE-2247: Added a CharArrayMap for performance improvements in some stemmers and synonym filters. (Uwe Schindler) +* LUCENE-2314: Added AttributeSource.copyTo(AttributeSource) that + allows to use cloneAttributes() and this method as a replacement + for captureState()/restoreState(), if the state itsself + needs to be inspected/modified. (Uwe Schindler) + Optimizations * LUCENE-2075: Terms dict cache is now shared across threads instead Index: src/java/org/apache/lucene/util/AttributeSource.java =================================================================== --- src/java/org/apache/lucene/util/AttributeSource.java (revision 922585) +++ src/java/org/apache/lucene/util/AttributeSource.java (working copy) @@ -365,8 +365,10 @@ do { AttributeImpl targetImpl = attributeImpls.get(state.attribute.getClass()); - if (targetImpl == null) - throw new IllegalArgumentException("State contains an AttributeImpl that is not in this AttributeSource"); + if (targetImpl == null) { + throw new IllegalArgumentException("State contains AttributeImpl of type " + + state.attribute.getClass() + " that is not in in this AttributeSource"); + } state.attribute.copyTo(targetImpl); state = state.next; } while (state != null); @@ -450,24 +452,45 @@ * with exactly the same attributes (using {@link #AttributeSource(AttributeSource)}) */ public AttributeSource cloneAttributes() { - AttributeSource clone = new AttributeSource(this.factory); + final AttributeSource clone = new AttributeSource(this.factory); - // first clone the impls if (hasAttributes()) { + // first clone the impls if (currentState == null) { computeCurrentState(); } for (State state = currentState; state != null; state = state.next) { clone.attributeImpls.put(state.attribute.getClass(), (AttributeImpl) state.attribute.clone()); } + + // now the interfaces + for (Entry, AttributeImpl> entry : this.attributes.entrySet()) { + clone.attributes.put(entry.getKey(), clone.attributeImpls.get(entry.getValue().getClass())); + } } - // now the interfaces - for (Entry, AttributeImpl> entry : this.attributes.entrySet()) { - clone.attributes.put(entry.getKey(), clone.attributeImpls.get(entry.getValue().getClass())); - } - return clone; } + + /** + * Copies the contents of this AttributeSource to the given target. This only works + * if the target uses the same {@link AttributeFactory} and contains at least the + * same {@link AttributeImpl}s this AttributeSource provides. + */ + public final void copyTo(AttributeSource target) { + if (hasAttributes()) { + if (currentState == null) { + computeCurrentState(); + } + for (State state = currentState; state != null; state = state.next) { + final AttributeImpl targetImpl = target.attributeImpls.get(state.attribute.getClass()); + if (targetImpl == null) { + throw new IllegalArgumentException("This AttributeSource contains AttributeImpl of type " + + state.attribute.getClass() + " that is not in the target"); + } + state.attribute.copyTo(targetImpl); + } + } + } } Index: src/test/org/apache/lucene/util/TestAttributeSource.java =================================================================== --- src/test/org/apache/lucene/util/TestAttributeSource.java (revision 922585) +++ src/test/org/apache/lucene/util/TestAttributeSource.java (working copy) @@ -95,6 +95,18 @@ assertNotSame("TypeAttribute of original and clone must be different instances", typeAtt2, typeAtt); assertEquals("TermAttribute of original and clone must be equal", termAtt2, termAtt); assertEquals("TypeAttribute of original and clone must be equal", typeAtt2, typeAtt); + + // test copy back + termAtt2.setTermBuffer("OtherTerm"); + typeAtt2.setType("OtherType"); + clone.copyTo(src); + assertEquals("TermAttribute of original must now contain updated term", "OtherTerm", termAtt.term()); + assertEquals("TypeAttribute of original must now contain updated type", "OtherType", typeAtt.type()); + // verify again: + assertNotSame("TermAttribute of original and clone must be different instances", termAtt2, termAtt); + assertNotSame("TypeAttribute of original and clone must be different instances", typeAtt2, typeAtt); + assertEquals("TermAttribute of original and clone must be equal", termAtt2, termAtt); + assertEquals("TypeAttribute of original and clone must be equal", typeAtt2, typeAtt); } public void testToStringAndMultiAttributeImplementations() {