[jdom-interest] JDom and Java5

Victor Toni victor.toni at ebuconnect.de
Tue Feb 26 04:57:19 PST 2008


Hi Rolf,

have you tried the approach I mentioned in the previous mail. It doesn't 
seem to impose changes on the user but gives him flexibility.

For convenience the mentioned code snippet:

 public <T> List<T> selectNodes(Object context) throws JDOMException {
    try {
       currentContext = context;
       return xPath.selectNodes(context);
    } catch (JaxenException ex1) {
       throw new JDOMException("XPath error while evaluating \"" + 
xPath.toString() + "\": " + ex1.getMessage(), ex1);
    } finally {
       currentContext = null;
    }
 }


Kindest regards,
Victor

Rolf Lear wrote:
> Hi All.
>
> I spent a fair bit of time playing with things over the weekend, and 
> have decided that making generic versions of the selectNodes process 
> is somewhat possible if we change the API a lot, but, at some point 
> there has to be an explicit cast of either the content of a list, or 
> the list itself. Currently there are no Compiler errors or warnings in 
> the Java5 JDom, and these changes would require us to tolerate a 
> compiler warning at some point. As long as we use Jaxen I see no 
> alternative. Then again, someone may take an approach different to the 
> ones I have tried, and come up with something that works well.
>
> The alternatives as I see them are:
> a) explicitly casting the returned List from Jaxen to a List<type>, 
> and then returning the List<type> to the user, at which point, if 
> there is a mismatch between the content type the user claims is in the 
> list, and the actual content of the list, then there will be a 
> ClassCastException when the user reads the List<type>. I see this as 
> being unacceptable. A modification to this would be to check each 
> element of the list before returning it to the user at which point the 
> ClassCastException will happen inside the JDom API and this would be 
> better, but also add a processing overhead and require a significant 
> (not recompile-compatible) change to the API method signatures.
> b) creating a List<Type> and then checking and casting each element of 
> the Jaxen List result, and adding these to the List<Type>, but will 
> add a processing overhead. This will also require 
> non-recompile-compatible changes to the API.
>
> For the moment I am giving up on trying to get a clean way to 
> transform the data in to a more meaningful result. "The Right Thing" 
> is hard to guarantee without big API changes as far as I can tell.
>
> It would be great if someone else could give it a go to confirm this.
>
> For the moment I am leaving the code unchanged to return List<?> until 
> someone comes up with something better.
>
> Rolf
>
> Rolf wrote:
>> Hi Mattias.
>>
>> Thanks for that. I's made me look further in to things than I had 
>> before. I put together some test code and I see what you mean about 
>> casting the results. I have been in the habit of coding using 
>> eclipse, and I set strict compiler warnings and as a result I see 
>> lots of errors/warnings generated by eclipse. I always try to resolve 
>> every issue in my code..... and using raw types always produces 
>> warnings. This would explain my reluctance for returning just plain 
>> List. It is a raw type and should be avoided. At the same time, I 
>> realize now that returning List<Object> has it's drawbacks in that 
>> you can't cast it to anything directly either... although you can 
>> actually get away with a double-cast .... List<Element> mylist = 
>> (List<Element>)(List<?>)(new ArrayList<Object>());
>>
>> By using plain List it introduces compile-time warnings in to JDom. I 
>> would prefer to avoid that at all costs. It should be the client side 
>> that encounters the warnings, not the API side.
>>
>> I am content with returning List<?> or List<? extends Object> for the 
>> return type. It indicates that the process has been thought through. 
>> It would also be real interesting to explore turning the entire XPath 
>> class in to a generic object.... I'm going to play a little bit and 
>> get back.
>>
>> I think there is a fair amount of food for thought. Right now the API 
>> returns List<?> and this should remove any compile-time issues anyone 
>> has with the jar, so, for those interested, it is not a hurdle....
>>
>> Rolf
>>
>> Mattias Jiderhamn wrote:
>>> (To be completely honest I have not read the whole post Rolf...)
>>>
>>> Without having analyzed if this depends on some compiler parameter 
>>> or other project setting, here is what I experienced.
>>>
>>> With return type List (as JDOM is today) I could do
>>> List<Element> elements = XPath.selectNodes(doc, path)
>>> and only get compiler warnings
>>>
>>> With return type List<?> (Rolfs second version;  which I believe are 
>>> equivalent to List<? extends Object>) I could do
>>>  List<Element> elements = (List<Element>) XPath.selectNodes(doc, path)
>>>
>>> With return type List<Object> I cannot cast but have to do
>>> List<Element> elements = new ArrayList<Element>();
>>> for(Object o : XPath.selectNodes(doc, path))
>>>  elements.add((Element)o);
>>>
>>> I think the last option is by far the least appealing (unless, as I 
>>> said, there is some setting to fix this).
>>> In the choice between List and List<?>/List<? extends Object> the 
>>> plain List has the advantage of making the Java5 port more of a JAR 
>>> replacement. It does not require modifying the code to add the cast. 
>>> Also, Gregor points out that List is for "pre-generics legacy code" 
>>> and certainly, in this case it could be used to indicate that 
>>> behinds the scenes there is pre-generics legacy code, which in this 
>>> case is Jaxen.
>>>
>>> Therefore I personally vote for "List".
>>>
>>> BUT there is actually a fourth alternative; add the expected output 
>>> type as a parameter to the method.
>>> List<Element> elements = XPath.selectNodes(doc, path, Element.class);
>>> List<Attribute> elements = XPath.selectNodes(doc, path, 
>>> Attribute.class);
>>> List<Object> elements = XPath.selectNodes(doc, path, Object.class); 
>>> // Mix of different types
>>> This may be the most beautiful solution, but also the most 
>>> noticeable change with a new parameter. What about an overload with 
>>> one legacy version with List and one with the third parameter???
>>>
>>> /Mattias
>>>
>>>
>>> Rolf wrote (2008-02-23 15:51):
>>>> Hi Gregor
>>>>
>>>> Hmm... actually, I somewhat disagree (in this particular 
>>>> circumstance). I have been thinking about this a bit more
>>>>
>>>> Here's the 'current' code behind the method (after I modified it 
>>>> yesterday)...
>>>>
>>>>   public List<?> selectNodes(Object context) throws JDOMException {
>>>>      try {
>>>>         currentContext = context;
>>>>         return xPath.selectNodes(context);
>>>>      } catch (JaxenException ex1) {
>>>>         throw new JDOMException("XPath error while evaluating \"" + 
>>>> xPath.toString() + "\": " + ex1.getMessage(), ex1);
>>>>      } finally {
>>>>         currentContext = null;
>>>>      }
>>>>   }
>>>>
>>>> Here's the signature on the xPath method that is supplied by Jaxen:
>>>>
>>>> List <http://java.sun.com/j2se/1.4.2/docs/api/java/util/List.html> 
>>>> *selectNodes*(Object 
>>>> <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html> 
>>>> context) throws JaxenException 
>>>> <http://jaxen.codehaus.org/apidocs/org/jaxen/JaxenException.html>
>>>>
>>>> Given that XPath can return all sorts of values (not all of them 
>>>> are JDom Content (like Attribute which is not Content)), then we 
>>>> have a real problem with this method.
>>>>
>>>> There is no way I can see (even by modifying Jaxen) to return a 
>>>> list of any specific type other than Object. It would be real nice 
>>>> if an xpath that returned just Elements would have a return type of 
>>>> List<Element>, but that just isn't feasible.
>>>>
>>>> The next best thing is to return something appropriate, and that 
>>>> should be the same as what Jaxen would return if it were Generified.
>>>>
>>>> Thus, the best thing would be to consider things from Jaxen's POV, 
>>>> and let the 'client' sort it out.
>>>>
>>>> Since Jaxen does not know anything about the actual content in the 
>>>> 'context' (it is all delegated to a JDom specific implementation), 
>>>> and that implementation has to be able to return both Attribute and 
>>>> Content, the best that Jaxen could do is return List<Object>.
>>>>
>>>> The Jaxen code would have no option but to look something like:
>>>>
>>>> List<Object> ret = new XXXList<Object>();
>>>> for (..... nodes in context ...) {
>>>>  if (... node matches the xpath ...) {
>>>>     ret.add(node);
>>>>  }
>>>> }
>>>>
>>>>
>>>> because it will potentially have to add Attributes, Elements, Text, 
>>>> etc. (and that's just for JDom, for other API's it will need other 
>>>> constructs).
>>>>
>>>> As a consequence, the Jaxen code, if it were Generified, would have 
>>>> no option but to return List<Object> from the method, just like it 
>>>> returns Object from the method selectSingleNode();
>>>>
>>>> Object 
>>>> <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html> 
>>>> *selectSingleNode*(Object 
>>>> <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html> 
>>>> context) throws JaxenException 
>>>> <http://jaxen.codehaus.org/apidocs/org/jaxen/JaxenException.html>
>>>>
>>>> In other words, I have come back around the circle and I believe 
>>>> that the method should return exactly List<Object> rather than 
>>>> List<?> or List<? extends Object>.
>>>>
>>>> As further considerations against the alternatives:
>>>>
>>>> returning List<? extends Object> implies that the actual returned 
>>>> list may be any other specific type as well, e.g. List<String> or 
>>>> List<Element> or even something silly like List<System>. This will 
>>>> not be the case, the actual returned type will in fact be 
>>>> List<Object> and there is no point in making it more obscure by 
>>>> saying List<? extends Object> because that actually reduces the 
>>>> meaning.
>>>>
>>>> returning List<?> implies that we have no idea what's in the list, 
>>>> but we do.
>>>>
>>>> The logical answer appears to be returning List<Object>. This makes 
>>>> the most sense until Jaxen finds a way for the method 
>>>> returnSingleNode(Context) to return a type other than Object. 
>>>> Here's the Jaxen code:
>>>>
>>>>    public Object selectSingleNode(Object node) throws JaxenException {
>>>>        List results = selectNodes( node );
>>>>        if ( results.isEmpty() ) {
>>>>            return null;
>>>>        }
>>>>        return results.get( 0 );
>>>>    }
>>>>
>>>> If Jaxen can be generified to have something like:
>>>>
>>>>    public T <T extends Object> selectSingleNode(Object node) throws 
>>>> JaxenException {
>>>>        List<T> results = selectNodes( node );
>>>>        if ( results.isEmpty() ) {
>>>>            return null;
>>>>        }
>>>>        return results.get( 0 );
>>>>    }
>>>>
>>>> only then should we consider the alternatives....
>>>>
>>>> On the other hand, the client-side code calling the XPath method is 
>>>> going to have to jump through all sorts of instanceof hoops 
>>>> anyways, and the return type does not really affect that in any way.
>>>>
>>>> As for Mattias's original claim that List<?> can be cast to 
>>>> List<Element> if you know the content will be only Elements, then, 
>>>> I believe that lends a certain weight to List<?>, but, is the same 
>>>> not true for List<Object>? At some point you will have a 
>>>> compile-time warning about unchecked types... unless you do 
>>>> individual casts to Element on the contents of the List anyway.
>>>>
>>>> Does this make sense? This whole topic is somewhat interesting, and 
>>>> I do see the value in different implementations. There appears to 
>>>> be more than one right answer, all with different compromises. At 
>>>> the moment I am more in the List<Object> camp but am willing to be 
>>>> convinced otherwise....
>>>>
>>>> Rolf
>>>>
>>>> Gregor Zeitlinger wrote:
>>>>> I think List<? extends Object> is more appropriate.
>>>>>
>>>>> It shows that the code has been generified (as opposed to using a 
>>>>> plain List).
>>>>> It's similiar to List<?>, but shows that Object is indeed the least
>>>>> common denomiator.
>>>>> _______________________________________________
>>>>> To control your jdom-interest membership:
>>>>> http://www.jdom.org/mailman/options/jdom-interest/youraddr@yourhost.com 
>>>>>
>>>>>
>>>>>   
>>>>
>>>
>>
>> _______________________________________________
>> To control your jdom-interest membership:
>> http://www.jdom.org/mailman/options/jdom-interest/youraddr@yourhost.com
>>
>
>
> _______________________________________________
> To control your jdom-interest membership:
> http://www.jdom.org/mailman/options/jdom-interest/youraddr@yourhost.com


-- 
Victor Toni
Senior Software Architect
    
Phone:  +49 203  9414768
Office: +49 2181 2363-0
Fax:    +49 2181 2363-43
Mobile: +49 160  8511835

Web: www.ebuconnect.de
Mail: victor.toni at ebuconnect.de

Sitz der Gesellschaft: ebuconnect AG, Stadttor 1, D-40219 Düsseldorf Amtsgericht Düsseldorf: HRB 40219
Vorstand: Andreas Weiss - Vorsitzender
Vorsitzender des Aufsichtsrates: Dr. Marc Henze



More information about the jdom-interest mailing list