I will work tomorrow on a patch with sophisticated backwards for 3.x and merge to trunk without sophisticated things g.
I changed my mind a little bit: I would simplify the whole thing: AttributeSource and AttributeImpl should have a simple method:
The default code would simply look like AttributeImpl.toString() now and add all non-static fields to the impl - special attributes like CharTermAttribute would have special handling. The default toString() [if not overridden] would simply call this method, too and pass a Fake-Map to the addToMap() method to populate a StringBuilder in Map.put() [to not automatically create a real Map always).
Code in analysis.jsp would simply pass a map (e.g. a LinkedHashMap to preserve order) and then print it out. The values in the map are native types / or CharSequence for (Char)TermAttribute.
The only problem with this aproach would be that the attribute keys must be unique - an idea would be to prefix them with the attribute name.
I will also remove the abstract equals() and hashCode() in AttributeImpl - the attribute API does not rely on them to be implemented - this simplyfies implementation of attributes, because equals/hashCode are never used. In 4.0 I would remove this from all custom attributes.
What do you think?