1 package com.fasterxml.jackson.databind.ext;
2 
3 import javax.xml.datatype.*;
4 import javax.xml.namespace.QName;
5 
6 import com.fasterxml.jackson.databind.*;
7 import com.fasterxml.jackson.databind.ext.CoreXMLDeserializers;
8 import com.fasterxml.jackson.databind.type.TypeFactory;
9 
10 /**
11  * Core XML types (javax.xml) are considered "external" (or more precisely "optional")
12  * since some Java(-like) platforms do not include them: specifically, Google AppEngine
13  * and Android seem to skimp on their inclusion. As such, they are dynamically loaded
14  * only as needed, and need bit special handling.
15  *
16  * @author tatu
17  */
18 public class TestCoreXMLTypes
19     extends BaseMapTest
20 {
21     /*
22     /**********************************************************
23     /* Serializer tests
24     /**********************************************************
25      */
26 
testQNameSer()27     public void testQNameSer() throws Exception
28     {
29         QName qn = new QName("http://abc", "tag", "prefix");
30         assertEquals(quote(qn.toString()), serializeAsString(qn));
31     }
32 
testDurationSer()33     public void testDurationSer() throws Exception
34     {
35         DatatypeFactory dtf = DatatypeFactory.newInstance();
36         // arbitrary value
37         Duration dur = dtf.newDurationDayTime(false, 15, 19, 58, 1);
38         assertEquals(quote(dur.toString()), serializeAsString(dur));
39     }
40 
testXMLGregorianCalendarSerAndDeser()41     public void testXMLGregorianCalendarSerAndDeser() throws Exception
42     {
43         DatatypeFactory dtf = DatatypeFactory.newInstance();
44         XMLGregorianCalendar cal = dtf.newXMLGregorianCalendar
45             (1974, 10, 10, 18, 15, 17, 123, 0);
46         /* Due to [JACKSON-308], 1.6 will use configurable Date serialization;
47          * and it defaults to using timestamp. So let's try couple of combinations.
48          */
49         ObjectMapper mapper = new ObjectMapper();
50         long timestamp = cal.toGregorianCalendar().getTimeInMillis();
51         String numStr = String.valueOf(timestamp);
52         assertEquals(numStr, mapper.writeValueAsString(cal));
53 
54         // [JACKSON-403] Needs to come back ok as well:
55         XMLGregorianCalendar calOut = mapper.readValue(numStr, XMLGregorianCalendar.class);
56         assertNotNull(calOut);
57         assertEquals(timestamp, calOut.toGregorianCalendar().getTimeInMillis());
58 
59         // and then textual variant
60         mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
61         // this is ALMOST same as default for XMLGregorianCalendar... just need to unify Z/+0000
62         String exp = cal.toXMLFormat();
63         String act = mapper.writeValueAsString(cal);
64         act = act.substring(1, act.length() - 1); // remove quotes
65         exp = removeZ(exp);
66         act = removeZ(act);
67         assertEquals(exp, act);
68     }
69 
removeZ(String dateStr)70     private String removeZ(String dateStr) {
71         if (dateStr.endsWith("Z")) {
72             return dateStr.substring(0, dateStr.length()-1);
73         }
74         if (dateStr.endsWith("+0000")) {
75             return dateStr.substring(0, dateStr.length()-5);
76         }
77         if (dateStr.endsWith("+00:00")) {
78             return dateStr.substring(0, dateStr.length()-6);
79         }
80         return dateStr;
81     }
82 
83     /*
84     /**********************************************************
85     /* Deserializer tests
86     /**********************************************************
87      */
88 
89     // First things first: must be able to load the deserializers...
testDeserializerLoading()90     public void testDeserializerLoading()
91     {
92         CoreXMLDeserializers sers = new CoreXMLDeserializers();
93         TypeFactory f = TypeFactory.defaultInstance();
94         sers.findBeanDeserializer(f.constructType(Duration.class), null, null);
95         sers.findBeanDeserializer(f.constructType(XMLGregorianCalendar.class), null, null);
96         sers.findBeanDeserializer(f.constructType(QName.class), null, null);
97     }
98 
testQNameDeser()99     public void testQNameDeser() throws Exception
100     {
101         QName qn = new QName("http://abc", "tag", "prefix");
102         String qstr = qn.toString();
103         ObjectMapper mapper = new ObjectMapper();
104         assertEquals("Should deserialize to equal QName (exp serialization: '"+qstr+"')",
105                      qn, mapper.readValue(quote(qstr), QName.class));
106     }
107 
testCalendarDeser()108     public void testCalendarDeser() throws Exception
109     {
110         DatatypeFactory dtf = DatatypeFactory.newInstance();
111         XMLGregorianCalendar cal = dtf.newXMLGregorianCalendar
112             (1974, 10, 10, 18, 15, 17, 123, 0);
113         String exp = cal.toXMLFormat();
114         assertEquals("Should deserialize to equal XMLGregorianCalendar ('"+exp+"')", cal,
115                 new ObjectMapper().readValue(quote(exp), XMLGregorianCalendar.class));
116     }
117 
testDurationDeser()118     public void testDurationDeser() throws Exception
119     {
120         DatatypeFactory dtf = DatatypeFactory.newInstance();
121         // arbitrary value, like... say, 27d5h15m59s
122         Duration dur = dtf.newDurationDayTime(true, 27, 5, 15, 59);
123         String exp = dur.toString();
124         assertEquals("Should deserialize to equal Duration ('"+exp+"')", dur,
125                 new ObjectMapper().readValue(quote(exp), Duration.class));
126     }
127 }
128