1 package com.fasterxml.jackson.databind.ext; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import javax.xml.datatype.*; 7 import javax.xml.namespace.QName; 8 9 import com.fasterxml.jackson.core.*; 10 11 import com.fasterxml.jackson.databind.*; 12 import com.fasterxml.jackson.databind.deser.Deserializers; 13 import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer; 14 15 /** 16 * Container deserializers that handle "core" XML types: ones included in standard 17 * JDK 1.5. Types are directly needed by JAXB, but may be unavailable on some 18 * limited platforms; hence separate out from basic deserializer factory. 19 */ 20 public class CoreXMLDeserializers extends Deserializers.Base 21 { 22 /** 23 * Data type factories are thread-safe after instantiation (and 24 * configuration, if any); and since instantion (esp. implementation 25 * introspection) can be expensive we better reuse the instance. 26 */ 27 final static DatatypeFactory _dataTypeFactory; 28 static { 29 try { 30 _dataTypeFactory = DatatypeFactory.newInstance(); 31 } catch (DatatypeConfigurationException e) { 32 throw new RuntimeException(e); 33 } 34 } 35 36 @Override findBeanDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc)37 public JsonDeserializer<?> findBeanDeserializer(JavaType type, 38 DeserializationConfig config, BeanDescription beanDesc) 39 { 40 Class<?> raw = type.getRawClass(); 41 if (raw == QName.class) { 42 return new Std(raw, TYPE_QNAME); 43 } 44 if (raw == XMLGregorianCalendar.class) { 45 return new Std(raw, TYPE_G_CALENDAR); 46 } 47 if (raw == Duration.class) { 48 return new Std(raw, TYPE_DURATION); 49 } 50 return null; 51 } 52 53 @Override // since 2.11 hasDeserializerFor(DeserializationConfig config, Class<?> valueType)54 public boolean hasDeserializerFor(DeserializationConfig config, Class<?> valueType) { 55 return (valueType == QName.class) 56 || (valueType == XMLGregorianCalendar.class) 57 || (valueType == Duration.class) 58 ; 59 } 60 61 /* 62 /********************************************************** 63 /* Concrete deserializers 64 /********************************************************** 65 */ 66 67 protected final static int TYPE_DURATION = 1; 68 protected final static int TYPE_G_CALENDAR = 2; 69 protected final static int TYPE_QNAME = 3; 70 71 /** 72 * Combo-deserializer that supports deserialization of somewhat optional 73 * javax.xml types {@link QName}, {@link Duration} and {@link XMLGregorianCalendar}. 74 * Combined into a single class to eliminate bunch of one-off implementation 75 * classes, to reduce resulting jar size (mostly). 76 * 77 * @since 2.4 78 */ 79 public static class Std extends FromStringDeserializer<Object> 80 { 81 private static final long serialVersionUID = 1L; 82 83 protected final int _kind; 84 Std(Class<?> raw, int kind)85 public Std(Class<?> raw, int kind) { 86 super(raw); 87 _kind = kind; 88 } 89 90 @Override deserialize(JsonParser p, DeserializationContext ctxt)91 public Object deserialize(JsonParser p, DeserializationContext ctxt) 92 throws IOException 93 { 94 // For most types, use super impl; but GregorianCalendar also allows 95 // integer value (timestamp), which needs separate handling 96 if (_kind == TYPE_G_CALENDAR) { 97 if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { 98 return _gregorianFromDate(ctxt, _parseDate(p, ctxt)); 99 } 100 } 101 return super.deserialize(p, ctxt); 102 } 103 104 @Override _deserialize(String value, DeserializationContext ctxt)105 protected Object _deserialize(String value, DeserializationContext ctxt) 106 throws IOException 107 { 108 switch (_kind) { 109 case TYPE_DURATION: 110 return _dataTypeFactory.newDuration(value); 111 case TYPE_QNAME: 112 return QName.valueOf(value); 113 case TYPE_G_CALENDAR: 114 Date d; 115 try { 116 d = _parseDate(value, ctxt); 117 } 118 catch (JsonMappingException e) { 119 // try to parse from native XML Schema 1.0 lexical representation String, 120 // which includes time-only formats not handled by parseXMLGregorianCalendarFromJacksonFormat(...) 121 return _dataTypeFactory.newXMLGregorianCalendar(value); 122 } 123 return _gregorianFromDate(ctxt, d); 124 } 125 throw new IllegalStateException(); 126 } 127 _gregorianFromDate(DeserializationContext ctxt, Date d)128 protected XMLGregorianCalendar _gregorianFromDate(DeserializationContext ctxt, 129 Date d) 130 { 131 if (d == null) { 132 return null; 133 } 134 GregorianCalendar calendar = new GregorianCalendar(); 135 calendar.setTime(d); 136 TimeZone tz = ctxt.getTimeZone(); 137 if (tz != null) { 138 calendar.setTimeZone(tz); 139 } 140 return _dataTypeFactory.newXMLGregorianCalendar(calendar); 141 } 142 } 143 } 144