jaxb-ri icon indicating copy to clipboard operation
jaxb-ri copied to clipboard

`xsi:nil` is implemented in a strange way

Open laeubi opened this issue 4 months ago • 3 comments

I currently hit a "bug" that really gives me a hard time to figure out:

If one reads a document and an element has xsi:nil set, this results in this element never changing its value.

This is because jakarta.xml.bind.JAXBElement.isNil() returns true whenever value is null or nil is true.

Now assume you de-serialize a document with something like:

<S xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

then call JAXBElement.setValue("balbla") with a non null value then isNil will return still true but the serializer writes it out as <S>balbla</S> (what is of course desired!)

I have no good idea how to really mitigate this, but it makes the method JAXBElement.isNil() almost useless to be used in client code, because:

  1. either nil is false in which case it return true if the value is null
  2. if nil is true it always return true regardless of what the value is

So from a code point of view I can of course write the value but the result is actually dependent on if the value is non null when serialize it. Reading the value on the other hand gives me nothing, as it reflects not the value of the attribute, so actually everywhere i would need to use JAXBElement#getValue anyways to be really sure what the outcome will be.

laeubi avatar Jul 14 '25 16:07 laeubi

There seem to be some other issue around nil as well: https://github.com/eclipse-ee4j/jaxb-ri/issues?q=is%3Aissue%20state%3Aopen%20nil

laeubi avatar Jul 14 '25 16:07 laeubi

I'm a little bit unsure if I get you right.

So from my understanding a element with nil is not allowed to have any value / child nodes, but attributes:

An element can be ·valid· without content if it has the attribute xsi:nil with the value true. An element so labeled must be empty, but can carry attributes if permitted by the corresponding complex type. -- https://www.w3.org/TR/xmlschema11-1/#xsi_nil

So if you would provide <element xsi:nil="true">value</element> it's against xml spec.

So checking for nil is not the same as checking for a value. If your xml is valid according the xml spec nil must not have any value.

For serialization I guess the developer should take care if what he's setting on a JAXBElement is valid or not. So setting a value and setting nil to true is illegal according to xml spec. The alternative would be that there's an exception or when setting a value nil is set to false or when setting nil the values are removed.

I'm not 100% sure if JAXB should take care of that. From my understanding the developer needs to take care of that the JAXB model is legal and not auto fix it.

asbachb avatar Jul 21 '25 22:07 asbachb

@asbachb yes I agree with

So checking for nil is not the same as checking for a value.

and this is of course important for the case of validation as you pointed out.

But that's the point it currently introduces some kind of asymmetry here because "isNil" does not check for the boolean alone (as in your example!) but also for the value being null.

So given your fragment above I would expect the following:

  1. The xml is read from the string and nil = true and value = "value"
  2. If I now validate the document I get an error as this is an invalid combination (probably something like content not allowed in nil element)
  3. Now I call setValue("blabla")
  4. And it becomes nil = false and value = "blabla"
  5. I can possibly validate again and now it is fine and written out as <element>value</element>

Currently, if we assume the fragment read from the given XML one would always call

setNil(false)
setValue("blabla")

then isNil return false but calling

setNil(false)
setValue(null)

returns true and that where we have the asymmetry!

Of course what is not only cumbersome but also easily forgotten to update both properties, it becomes really strange if we assume isNil was set to true (e.g. because it reads the value from your xml fragment) and you call

setValue("blabla")

isNil return true but the element is written out as <element>blabla</element> ...

laeubi avatar Jul 22 '25 07:07 laeubi