package com.fasterxml.jackson.databind.ext;

import java.io.IOException;
import java.util.Calendar;

import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.fasterxml.jackson.databind.ser.std.CalendarSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

Provider for serializers of XML types that are part of full JDK 1.5, but that some alleged 1.5 platforms are missing (Android, GAE). And for this reason these are added using more dynamic mechanism.

Note: since many of classes defined are abstract, caller must take care not to just use straight equivalency check but rather consider subclassing as well.

/** * Provider for serializers of XML types that are part of full JDK 1.5, but * that some alleged 1.5 platforms are missing (Android, GAE). * And for this reason these are added using more dynamic mechanism. *<p> * Note: since many of classes defined are abstract, caller must take * care not to just use straight equivalency check but rather consider * subclassing as well. */
public class CoreXMLSerializers extends Serializers.Base { @Override public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc) { Class<?> raw = type.getRawClass(); if (Duration.class.isAssignableFrom(raw) || QName.class.isAssignableFrom(raw)) { return ToStringSerializer.instance; } if (XMLGregorianCalendar.class.isAssignableFrom(raw)) { return XMLGregorianCalendarSerializer.instance; } return null; } @SuppressWarnings("serial") public static class XMLGregorianCalendarSerializer extends StdSerializer<XMLGregorianCalendar> implements ContextualSerializer { final static XMLGregorianCalendarSerializer instance = new XMLGregorianCalendarSerializer(); final JsonSerializer<Object> _delegate; public XMLGregorianCalendarSerializer() { this(CalendarSerializer.instance); } @SuppressWarnings("unchecked") protected XMLGregorianCalendarSerializer(JsonSerializer<?> del) { super(XMLGregorianCalendar.class); _delegate = (JsonSerializer<Object>) del; } @Override public JsonSerializer<?> getDelegatee() { return _delegate; } @Override public boolean isEmpty(SerializerProvider provider, XMLGregorianCalendar value) { return _delegate.isEmpty(provider, _convert(value)); } @Override public void serialize(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider) throws IOException { _delegate.serialize(_convert(value), gen, provider); } @Override public void serializeWithType(XMLGregorianCalendar value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer) throws IOException { // 16-Aug-2021, tatu: as per [databind#3217] we cannot simply delegate // as that would produce wrong Type Id altogether. So redefine // implementation from `StdScalarSerializer` // _delegate.serializeWithType(_convert(value), gen, provider, typeSer); // Need not really be string; just indicates "scalar of some kind" // (and so numeric timestamp is fine as well): WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, // important! Pass value AND type to use typeSer.typeId(value, XMLGregorianCalendar.class, JsonToken.VALUE_STRING)); // note: serialize() will convert to delegate value serialize(value, g, provider); typeSer.writeTypeSuffix(g, typeIdDef); } @Override public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException { _delegate.acceptJsonFormatVisitor(visitor, null); } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { JsonSerializer<?> ser = prov.handlePrimaryContextualization(_delegate, property); if (ser != _delegate) { return new XMLGregorianCalendarSerializer(ser); } return this; } protected Calendar _convert(XMLGregorianCalendar input) { return (input == null) ? null : input.toGregorianCalendar(); } } }