mercoledì 6 febbraio 2013

JAXBElement.isNil() returns confusing value

Actually, it doesn't, but we'll come to that later.

Take this example: you have to read an XML document (a SOAPMessage received as a response from a Web Service, for example) and to instantiate some objects accordingly. A certain element may be null, and in this case you have to skip the creation of that object.

 You're currently working using JAX-WS and its JAXBElement objects to manipulate data.





Example 1: XML-excerpt with data
<a:Messages>
  <a:BusinessMessage>
    <a:Culture>it</a:Culture>
    <a:Key>SomeKey</a:Key>
    <a:Value>SomeValue</a:Value>
  </a:BusinessMessage>
</a:Messages>
Let's assume that you want to create an object representing the BusinessMessage node, but only if it has data. You have your nice JAXBElement object that represents it, so you just have to test if its content.
Taking a look at JAXBElement document you see the isNil() method. Its Javadoc description says:
Returns true iff this element instance content model is nil.

This property always returns true when getValue() is null. Note that the converse is not true, when this property is true, getValue() can contain a non-null value for attribute(s). It is valid for a nil xml element to have attribute(s).
Oh, nice, when it has no value it returns true. It looks like what I need, so I can write something like this:
Messages m = response.getMessages().getValue();
BusinessMessage bm = m.getBusinessMessage().isNil()
      ? null :
m.getBusinessMessage().getValue();
It sounds right, doesn't it? Well, after a few attempts, some strange behaviour in your application starts to occur. After a long inspection, you find out that isNil() is returning, at times, the wrong value. Or, the value you didn't expect it to return: even with a valorized BusinessMessage it sometimes returns "true".

What's going on?

Let's look back at the function Javadoc comment: "This property always returns true when getValue() is null". It actually doesn't imply that when getValue() is not null, then the property returns false.
The following statement actually blows a whistle, but it's a bit misleading, because it describes a case in which the property returns "true" and it is about attributes, not value. You may have overlooked it (as I did) when you chose to use this property for testing purposes.

Long story short, the test you need to do is on the getValue() property. And so, the above code fragment becomes:
Messages m = response.getMessages().getValue();
BusinessMessage bm =
        m.getBusinessMessage().getValue() == null
      ? null :
m.getBusinessMessage().getValue();
Little moral to learn: read comments *very* well; and write your own comments *very* well, because they may save other programmers' time (and headaches)!

Nessun commento:

Posta un commento