package com.fasterxml.jackson.databind.ext;
import java.io.IOException;
import java.util.*;
import javax.xml.datatype.*;
import javax.xml.namespace.QName;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.Deserializers;
import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
/**
* Container deserializers that handle "core" XML types: ones included in standard
* JDK 1.5. Types are directly needed by JAXB, but may be unavailable on some
* limited platforms; hence separate out from basic deserializer factory.
*/
public class CoreXMLDeserializers extends Deserializers.Base
{
/**
* Data type factories are thread-safe after instantiation (and
* configuration, if any); and since instantion (esp. implementation
* introspection) can be expensive we better reuse the instance.
*/
final static DatatypeFactory _dataTypeFactory;
static {
try {
_dataTypeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new RuntimeException(e);
}
}
@Override
public JsonDeserializer<?> findBeanDeserializer(JavaType type,
DeserializationConfig config, BeanDescription beanDesc)
{
Class<?> raw = type.getRawClass();
if (raw == QName.class) {
return new Std(raw, TYPE_QNAME);
}
if (raw == XMLGregorianCalendar.class) {
return new Std(raw, TYPE_G_CALENDAR);
}
if (raw == Duration.class) {
return new Std(raw, TYPE_DURATION);
}
return null;
}
/*
/**********************************************************
/* Concrete deserializers
/**********************************************************
*/
protected final static int TYPE_DURATION = 1;
protected final static int TYPE_G_CALENDAR = 2;
protected final static int TYPE_QNAME = 3;
/**
* Combo-deserializer that supports deserialization of somewhat optional
* javax.xml types {@link QName}, {@link Duration} and {@link XMLGregorianCalendar}.
* Combined into a single class to eliminate bunch of one-off implementation
* classes, to reduce resulting jar size (mostly).
*
* @since 2.4
*/
public static class Std extends FromStringDeserializer<Object>
{
private static final long serialVersionUID = 1L;
protected final int _kind;
public Std(Class<?> raw, int kind) {
super(raw);
_kind = kind;
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException
{
// For most types, use super impl; but GregorianCalendar also allows
// integer value (timestamp), which needs separate handling
if (_kind == TYPE_G_CALENDAR) {
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
return _gregorianFromDate(ctxt, _parseDate(p, ctxt));
}
}
return super.deserialize(p, ctxt);
}
@Override
protected Object _deserialize(String value, DeserializationContext ctxt)
throws IOException
{
switch (_kind) {
case TYPE_DURATION:
return _dataTypeFactory.newDuration(value);
case TYPE_QNAME:
return QName.valueOf(value);
case TYPE_G_CALENDAR:
Date d;
try {
d = _parseDate(value, ctxt);
}
catch (JsonMappingException e) {
// try to parse from native XML Schema 1.0 lexical representation String,
// which includes time-only formats not handled by parseXMLGregorianCalendarFromJacksonFormat(...)
return _dataTypeFactory.newXMLGregorianCalendar(value);
}
return _gregorianFromDate(ctxt, d);
}
throw new IllegalStateException();
}
protected XMLGregorianCalendar _gregorianFromDate(DeserializationContext ctxt,
Date d)
{
if (d == null) {
return null;
}
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(d);
TimeZone tz = ctxt.getTimeZone();
if (tz != null) {
calendar.setTimeZone(tz);
}
return _dataTypeFactory.newXMLGregorianCalendar(calendar);
}
}
}