[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