[jdom-interest] jdom 2.0 with generics

Jason Hunter jhunter at servlets.com
Fri Jul 22 13:33:27 PDT 2011


Rolf's been sending in good code for as long as I can remember.  :)

The reason I've resisted jumping on generics was the backward compatibility problem.  It's just something you can do without breaking old code, as Rolf's email explains in some good detail.

I do think it's causing JDOM to be seen in a negative light, so we should do something about it.

The alternative package approach is probably the best road forward.  It's a bit uglier, but it makes explicit the breakage, and means you can use JDOM 1.1 and JDOM 2.0 classes in the same project without conflict (an issue that arises if a project uses both Library X and Library Y which both depend on JDOM and maybe not the same versions).

I suppose org.jdom2 is the best package.  Suitable for a 2.0 release.

I don't have a lot of time to do coding but I'll be happy to coordinate.  Rolf, why don't you send me the code and I'll put it in revision control.  Some others have sent in versions as well.  We can decide which one's best and work on a 2.0 release.

Maybe we should move the code to github while we're at it?

Send in thoughts...

-jh-

On Jul 21, 2011, at 4:56 PM, Rolf Lear wrote:

> As an overview of what I did:
> 
> README.Java5
> ============
> 
> Here are the more significant changes made for the Java5 proposed solution.
> 
> 1. Modified org.jdom.filter.Filter to be generic.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This allows Filter Implementations to return specific Content types.
> In addition, instead of returning boolean, it instead must fulfill the contract to return the input content cast in to
> the same type as the Filter <T>. Returning a null value indicates the filter does not match.
>  
> public interface Filter <T extends Content> extends java.io.Serializable {
>     public T filter(Content content);
> }
> 
> Here is the JDom1.1 interface:
> public interface Filter extends java.io.Serializable {
>     public boolean matches(Object obj);
> }
> 
> Significant implications of this change include the change of the method name from 'matches' to 'filter'.
> This is somewhat mitigated by the 'AbstractFilter' method 'matches' which is simply:
>     return filter(content) != null;
>     
> Another 'regression' is that the filter and matches method now require at least 'Content' instead of 'Object' data.
> A direct implication of this is that you can not have a Filter on Document Objects. I could not find any examples of
> this in the project, or my work environment. It seems to be somewhat 'safe'. This is especially true because Filters
> are primarily used as input to the Parent.getContent(Filter) method, which, since the content can never be Document,
> implies this change is probably benign. It does make some code redundant in class ContentFilter.
> 
> All classes that implement Filter have been modified to be sensible.
> 
> This is the change that makes the code:
>     List<Element> kids = someelement.getChildren();
> possible.
> 
> 
> 2. Modified Parent to be generic.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> This allows for the method:
>     Parent<T> addContent(Content content)
> to be added to the Parent interface, and still return the right type... 
> 
> 
> 2. Rewrote much of ContentList (again)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Three motivators for this change:
>   a) Generics - so much had to change to accomodate Generics, seems this was the core impact.
>   b) Compliance - set() method on Collections are not supposed to impact Concurrent Modification,
>      but JDom did. Changed this so that set() does not impact concurrent status.
>   c) Performance - modified FilterList and FilterListIterator to work on an as-needed basis. Will
>      cache known content, but will only filter data on an as-needed basis, or 'lazy' basis. Need to
>      devise tests to measure performance impact, but things like element.getChildren.iterator() will be
>      much faster.
>      
> Another motivator was conformance with existing concepts, specifically List.subList(int,int). The paradigm for
> SubList is that modifications to the base list would cause concurrent exception in subList. This seems to be
> appropriate for FilterLists too, but, too much code depends on essentially dynamic/concurrent modification
> to make the change. The old behaviour remains.... leading to potentially odd things in FilterList iterators. 
> 
> 
> 3. Removed complexities in JDOMException
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> In Java5 we have the initCause method embedded in to Throwable. We don't need to jump through hoops any more.
> 
> 
> 4. Removed TextBuffer class
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This was an attempt to be a better performing StringBuffer. With Java5's StringBuilder, we don't need to worry.
> 
> 
> 5. Created AttributeType Enum
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This makes new attributes easy to manage, and also eliminates a bunch of org.jdom.test.* stuff.
> This also has probably the largest impact on existing code because of the requriement to change things like
>     Attribute att = new Attribute ("name", "somevalue", Attribute.ID_TYPE);
> to
>     Attribute att = new Attribute ("name", "somevalue", AttributeType.ID_TYPE);
>     
> On the other hand, it is all now TypeSafe ;-)
> 
> 
> 6. Created Annotation CVS_ID
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This is used instead of the static field CVS_ID. This is set up to be an annotation to a class. Previously we had:
> 	public class Attribute implements Serializable, Cloneable {
> 		private static final String CVS_ID = "@(#) $RCSfile: Attribute.java,v $ $Revision: 1.56 $ $Date: 2007/11/10 05:28:58 $ $Name:  $";
> 		....		
> 
> we now instead have:
> 	@CVS_ID("@(#) $RCSfile: Attribute.java,v $ $Revision: 1.56 $ $Date: 2007/11/10 05:28:58 $ $Name:  $")
> 	public class Attribute implements Serializable, Cloneable {
> 
> The motivation for this is because Eclipse complains when there are unused private members... but, this is perfect
> fodder for annotations.
> 
> As a result, all org.jdom.* classes in the main repo have been modified to use the annotation rather than the static String.
> 
> As an excercies later, we will be able to programatically be able to determing all the CVS details at runtime using
> the annotations, and I have tested that 
> 
> 
> 7. General Tidy-up.
> ^^^^^^^^^^^^^^^^^^^
> 
> Fixed all JavaDoc comments where applicable. Ensured @Override was specified where appropriate, etc.
> basically, I set strict rules in Eclipse, and then fixed all issues.
> 
> 
> 8. JavaDoc
> ^^^^^^^^^^
> All public and protected classes, methods, and fields have had their JavaDoc entries inspected and completed.
> 
> 
> 9. build.xml
> ^^^^^^^^^^^^
> 
> set Java compliance levels, JDom version number.
> 
> TESTS
> =====
> org.jdom.test.* has been modified to use and test the new code properly.
> Alltests was modified to include some suites that were not included.
> Alltests has been run, and all run tests have passed.
> 
> 
> CONTRIB
> =======
> All code has been modified to do what appears to be sane usage of the new JDom, but testing has not been done.
> 
> STILL TO DO
> ===========
> 
> FilterIterator seems clunky still. Especially the XXX warning.
> 
> 
> 
> 
> 
> 
> 
> On 21/07/2011 7:19 PM, Rolf Lear wrote:
>> 
>> I did a JDOM conversion a while back. Made the code available to those who were interested.
>> 
>> There are a few 'gotchas', and most of the Generics implementation relies on 'hiding' explicit casting inside of the ContentList class.
>> 
>> It makes code that compiles against the JDOM cleaner, but does not actually improve any reliability... 
>> 
>> Additionally, the XPath support is pretty much impossible to accomplish.
>> 
>> Let me dig up the code.... Or, rather, anyone interested should mail me directly.
>> 
>> Rolf
>> 
> 
> _______________________________________________
> To control your jdom-interest membership:
> http://www.jdom.org/mailman/options/jdom-interest/youraddr@yourhost.com




More information about the jdom-interest mailing list