FasterXML / jackson-dataformat-xml

Extension for Jackson JSON processor that adds support for serializing POJOs as XML (and deserializing from XML) as an alternative to JSON
Apache License 2.0
567 stars 221 forks source link

Unmarshalling `null` object still leaves the default initialised object in place #522

Closed mensinda closed 2 years ago

mensinda commented 2 years ago

Example:

package it;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

public class NullObj {
    public static class InnerDto {
        public String someStuff = "FooBar";
    }

    public static class DTO {
        public InnerDto iAmNull = new InnerDto(); // default is not null
        public InnerDto iAmNotNull = new InnerDto();
    }

    public static void main(String ... args) throws JsonProcessingException {
        DTO dto = new DTO();
        dto.iAmNull = null;

        XmlMapper mapper = new XmlMapper();

        final String res = mapper.writeValueAsString(dto);

        // <DTO><iAmNull/><iAmNotNull><someStuff>FooBar</someStuff></iAmNotNull></DTO>
        System.out.println(res);

        DTO reversed = mapper.readValue(res, DTO.class);

        // The following statement should produce a NullPointerException but prints `FooBar`!!!
        System.out.println(reversed.iAmNull.someStuff);
    }
}

jackson version: 2.13.2

mensinda commented 2 years ago

Digging further into this, I managed to get this working by manually changing the generated <iAmNull/> to <iAmNull xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>.

So, I did some further digging and found that I could get Jackson XML to emit this automatically with XmlMapper.builder().configure(ToXmlGenerator.Feature.WRITE_NULLS_AS_XSI_NIL, true).build();.

I am going to close this, since adding this option solved my issue, but I would still recommend to enable this by default (maybe a bit naive since this could be a breaking change) and / or document this in the README.md since I only found this by digging through the code.