javajacksongregorian-calendarxmlgregoriancalendar

Jackson polymorphic serialization generates an incorrect class name


When I use Jackson polymorphic serialization, it generates a JSON object with an incorrect fully qualified class name.

The code below serializes an XMLGregorianCalendar. The output is:

["java.util.GregorianCalendar",-3600000]

I expected the following:

["javax.xml.datatype.XMLGregorianCalendar",-3600000]

Why does it output java.util.GregorianCalendar?

Or more importantly: How do I fix this?

Code example:

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.ByteArrayOutputStream;

public class JacksonGregorianProblem {

    public static void main(String[] args) throws java.io.IOException, DatatypeConfigurationException {

        XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar();
        ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        mapper.writeValue(byteArrayOutputStream, xmlGregorianCalendar);

        System.out.println(byteArrayOutputStream);
    }
}

Solution

  • To get the expected behavior I have implemented a custom XMLGregorianCalendar serializer. This class takes care of the serialization of the XLMGregorianCalendar and now the output is exactly what I expect. :-)

    class XMLGregorianCalendarSerializer extends StdSerializer<XMLGregorianCalendar> {
    
        public XMLGregorianCalendarSerializer() {
            this(null);
        }
    
        public XMLGregorianCalendarSerializer(Class<XMLGregorianCalendar> t) {
            super(t);
        }
    
        @Override
        public void serialize(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider)
            throws IOException
        {
            gen.writeNumber(value.toGregorianCalendar().getTimeInMillis());
        }
    
        @Override
        public void serializeWithType(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider,
            TypeSerializer typeSerializer) throws IOException
        {
            gen.writeStartArray();
            gen.writeString("javax.xml.datatype.XMLGregorianCalendar");
            serialize(value, gen, provider); // call your customized serialize method
            gen.writeEndArray();
        }
    }
    

    You can add this serializer to the object mapper with the code below. It can be pasted in the code example in the question.

        SimpleModule module = new SimpleModule();
        module.addSerializer(XMLGregorianCalendar.class, new XMLGregorianCalendarSerializer());
        mapper.registerModule(module);