[jdom-interest] JDom and Java5

Rolf jdom at tuis.net
Wed Feb 27 06:54:20 PST 2008


Hi Mattias

See comments inline...

Mattias Jiderhamn wrote:
> Rolf wrote (2008-02-27 02:55):
>> On the other hand, I think it would also be a *very good* solution to 
>> leave the method with a return type of List<?> because, as far as I 
>> can tell, it is fully compile-time backward-compatible with existing 
>> code,  ... I am sure would be far more receptive to migrate to 
>> 'JDom2' if the migration was 'seamless'.
> Does this mean you managed to compile
>  List<Elements> l = XPath.selectNodes(...)
> if XPath.selectNodes() returns List<?>; the case where I had to add an 
> explicit cast in comparison with the old raw "List" version to avoid 
> "incompatible types" error?
> How?
>
No, but this is what I can do...

see the file 
http://git.tuis.net/?p=jdom.git;a=blob_plain;f=samples/XPathReader.java;hb=HEAD).

This has the code:

        // Print servlet information
        XPath servletPath = XPath.newInstance("//servlet");
        List servlets = servletPath.selectNodes(doc);

In it's current state, it gets a compiler warning that "List is a raw 
type. References to List<E> should be parameterized.".
Note that:

servletPath.selectNodes(doc);

returns the type List<?>

Now, the code following the above snippet is:

        out.println("This WAR has "+ servlets.size() +" registered 
servlets:");
        Iterator i = servlets.iterator();
        while (i.hasNext()) {
            Element servlet = (Element) i.next();
            out.print("\t" + servlet.getChild("servlet-name")
                                    .getTextTrim() +
                      " for " + servlet.getChild("servlet-class")
                                       .getTextTrim());
            List initParams = servlet.getChildren("init-param");
            out.println(" (it has " + initParams.size() + " init params)");
        }

The above construct is very typical of 'legacy' JDom and XPath usage.

So, by returning List<?>, there are only compile-time warnings in 
existing legacy code, and the only difference between JDom1.1 and JDom2 
is the details on the compiler warnings. But, if a person were to 
'upgrade' their legacy code, they could do so very easily with many 
options, including the following alternatives:

        XPath servletPath = XPath.newInstance("//servlet");
        List<Element> servlets = 
(List<Element>)servletPath.selectNodes(doc);

        out.println("This WAR has "+ servlets.size() +" registered 
servlets:");
        for (Element servlet : servlets) {
            out.print("\t" + servlet.getChild("servlet-name")
                                    .getTextTrim() +
                      " for " + servlet.getChild("servlet-class")
                                       .getTextTrim());
            List<Element> initParams = servlet.getChildren("init-param");
            out.println(" (it has " + initParams.size() + " init params)");
        }

This compiles just fine with a compile warning (unchecked cast) only on 
the single line: List<Element> servlets = 
(List<Element>)servletPath.selectNodes(doc);
This warning is exactly appropriate for the conditions and is a "good 
thing". It means that, if there are ClassCastExceptions in the for() 
loop, it was warned about at compile time. Id a pedantic programmer 
wanted to get rid of the warning, they could insert the @Suppress in 
their code.

Another option for the user would be 'the easy way':

        XPath servletPath = XPath.newInstance("//servlet");
        List<?> servlets = servletPath.selectNodes(doc);

        out.println("This WAR has "+ servlets.size() +" registered 
servlets:");
        Iterator<?> i = servlets.iterator();
        while (i.hasNext()) {
            Element servlet = (Element) i.next();
            out.print("\t" + servlet.getChild("servlet-name")
                                    .getTextTrim() +
                      " for " + servlet.getChild("servlet-class")
                                       .getTextTrim());
            List<Element> initParams = servlet.getChildren("init-param");
            out.println(" (it has " + initParams.size() + " init params)");
        }

There are no compiler errors or warnings with this, and the cast is done 
explicitly, and the behavior in this situation is identical to the 
'legacy' situation.

By having a List<?> return code the information returned from the API is 
100% accurate because the API has no idea of what the content of the 
List is, and it's the responsibility of the API user to deal with it 
appropriately.

This is a *good thing*.

The final situation is a programmer writing a new program... well, it 
would be ideal for them to be able to get methods that returned the 
correct types like List<Element> for xpaths that only return Elements. 
But, using the current Jaxen/JDom code this appears to be prohibitively 
complicated, and the constructs which would make it possible, like 
Victor's suggestion of:

    public <T> List<T> selectNodes(Object context)

does not actually solve the problem. All it does is make JDom look like 
the 'bad guy' when the programmer does something like:
   List<Element> elements = XPath.newInstance("//@*").selectNodes(document);

Leaving it as List<?> makes the programmer the 'bad guy' when he does:
  List<Element> elements = 
(List<Element>)XPath.newInstance("//@*").selectNodes(document);

The more I think about it the more I am convinced that JDom should let 
the programmer be clever about the interpretation of their own XPaths, 
and that way, when the programmer does something stupid, it's not JDom's 
fault when there are inconsistencies.
>
>> Based on previous postings of Jason's, I get the impression that 
>> Jason is somewhat reluctant to maintain two JDom code bases (the 
>> current build compatible back to Java1.2) and the 'new' build. 
>> Whatever happens we will need to convince Jason to do something with 
>> it... but, I imagine that the more interest people show the more 
>> likely we will get his attention on this.
> As has been said before; JDOM 1.1 is stable enough to be left as it is.
> I vote for moving forward with Java5/Generics and add new features 
> (like XPath 2.0) only to that branch.
>
>
>> Has anyone got any feedback on the utility of the rest of the API?
> After you fixed the initial issues it seems to work fine in my dev 
> environment, although I have not had time to look at it "under the 
> hood", and I probably won't find that time for quite a while.
>
> /Mattias
>

Thanks again.

Rolf


More information about the jdom-interest mailing list