Skip to content

Commit bbb5c99

Browse files
committed
Fix #3217 (XMLGregorianCalendar, polymorphic serialization)
1 parent c4d11f9 commit bbb5c99

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

release-notes/CREDITS-2.x

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,10 @@ Nick Benoit (nick-benoit14@github)
13661366
* Proposed #3193: Add `MapperFeature.APPLY_DEFAULT_VALUES`, initially for Scala module
13671367
(2.13.0)
13681368

1369+
Xinzhe Yang (xinzheyang@github)
1370+
* Reported #3217: `XMLGregorianCalendar` doesn't work with default typing
1371+
(2.13.0)
1372+
13691373
Kenneth Jorgensen (kennethjor@github)
13701374
* Requested #3238: Add PropertyNamingStrategies.UpperSnakeCaseStrategy
13711375
(and UPPER_SNAKE_CASE constant)

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ Project: jackson-databind
5858
(contributed by Klaas D)
5959
#3193: Add `MapperFeature.APPLY_DEFAULT_VALUES`, initially for Scala module
6060
(suggested by Nick B)
61+
#3217: `XMLGregorianCalendar` doesn't work with default typing
62+
(reported by Xinzhe Y)
6163
#3238: Add PropertyNamingStrategies.UpperSnakeCaseStrategy (and UPPER_SNAKE_CASE constant)
6264
(requested by Kenneth J)
6365
(contributed by Tanvesh)

src/main/java/com/fasterxml/jackson/databind/ext/CoreXMLSerializers.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import javax.xml.namespace.QName;
99

1010
import com.fasterxml.jackson.core.*;
11+
import com.fasterxml.jackson.core.type.WritableTypeId;
1112
import com.fasterxml.jackson.databind.*;
1213
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
1314
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
@@ -78,10 +79,22 @@ public void serialize(XMLGregorianCalendar value, JsonGenerator gen, SerializerP
7879
}
7980

8081
@Override
81-
public void serializeWithType(XMLGregorianCalendar value, JsonGenerator gen, SerializerProvider provider,
82+
public void serializeWithType(XMLGregorianCalendar value, JsonGenerator g, SerializerProvider provider,
8283
TypeSerializer typeSer) throws IOException
8384
{
84-
_delegate.serializeWithType(_convert(value), gen, provider, typeSer);
85+
// 16-Aug-2021, tatu: as per [databind#3217] we cannot simply delegate
86+
// as that would produce wrong Type Id altogether. So redefine
87+
// implementation from `StdScalarSerializer`
88+
// _delegate.serializeWithType(_convert(value), gen, provider, typeSer);
89+
90+
// Need not really be string; just indicates "scalar of some kind"
91+
// (and so numeric timestamp is fine as well):
92+
WritableTypeId typeIdDef = typeSer.writeTypePrefix(g,
93+
// important! Pass value AND type to use
94+
typeSer.typeId(value, XMLGregorianCalendar.class, JsonToken.VALUE_STRING));
95+
// note: serialize() will convert to delegate value
96+
serialize(value, g, provider);
97+
typeSer.writeTypeSuffix(g, typeIdDef);
8598
}
8699

87100
@Override

src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,8 @@ public void serialize(Object value, JsonGenerator gen, SerializerProvider provid
172172
public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider,
173173
TypeSerializer typeSer) throws IOException
174174
{
175-
/* 03-Oct-2012, tatu: This is actually unlikely to work ok... but for now,
176-
* let's give it a chance?
177-
*/
175+
// 03-Oct-2012, tatu: This is actually unlikely to work ok... but for now,
176+
// let's give it a chance?
178177
Object delegateValue = convertValue(value);
179178
JsonSerializer<Object> ser = _delegateSerializer;
180179
if (ser == null) {

src/test/java/com/fasterxml/jackson/databind/ext/MiscJavaXMLTypesReadWriteTest.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import javax.xml.namespace.QName;
55

66
import com.fasterxml.jackson.databind.*;
7+
import com.fasterxml.jackson.databind.testutil.NoCheckSubTypeValidator;
78
import com.fasterxml.jackson.databind.type.TypeFactory;
89

910
/**
@@ -17,24 +18,29 @@ public class MiscJavaXMLTypesReadWriteTest
1718
{
1819
private final ObjectMapper MAPPER = newJsonMapper();
1920

21+
private final ObjectMapper POLY_MAPPER = jsonMapperBuilder()
22+
.activateDefaultTyping(NoCheckSubTypeValidator.instance,
23+
ObjectMapper.DefaultTyping.NON_FINAL)
24+
.build();
25+
2026
/*
21-
/**********************************************************
27+
/**********************************************************************
2228
/* Serializer tests
23-
/**********************************************************
29+
/**********************************************************************
2430
*/
2531

2632
public void testQNameSer() throws Exception
2733
{
2834
QName qn = new QName("http://abc", "tag", "prefix");
29-
assertEquals(q(qn.toString()), serializeAsString(qn));
35+
assertEquals(q(qn.toString()), MAPPER.writeValueAsString(qn));
3036
}
3137

3238
public void testDurationSer() throws Exception
3339
{
3440
DatatypeFactory dtf = DatatypeFactory.newInstance();
3541
// arbitrary value
3642
Duration dur = dtf.newDurationDayTime(false, 15, 19, 58, 1);
37-
assertEquals(q(dur.toString()), serializeAsString(dur));
43+
assertEquals(q(dur.toString()), MAPPER.writeValueAsString(dur));
3844
}
3945

4046
public void testXMLGregorianCalendarSerAndDeser() throws Exception
@@ -76,13 +82,13 @@ private String removeZ(String dateStr) {
7682
}
7783
return dateStr;
7884
}
79-
85+
8086
/*
81-
/**********************************************************
87+
/**********************************************************************
8288
/* Deserializer tests
83-
/**********************************************************
89+
/**********************************************************************
8490
*/
85-
91+
8692
// First things first: must be able to load the deserializers...
8793
public void testDeserializerLoading()
8894
{
@@ -101,7 +107,7 @@ public void testQNameDeser() throws Exception
101107
qn, MAPPER.readValue(q(qstr), QName.class));
102108
}
103109

104-
public void testCalendarDeser() throws Exception
110+
public void testXMLGregorianCalendarDeser() throws Exception
105111
{
106112
DatatypeFactory dtf = DatatypeFactory.newInstance();
107113
XMLGregorianCalendar cal = dtf.newXMLGregorianCalendar
@@ -120,4 +126,23 @@ public void testDurationDeser() throws Exception
120126
assertEquals("Should deserialize to equal Duration ('"+exp+"')", dur,
121127
MAPPER.readValue(q(exp), Duration.class));
122128
}
129+
130+
/*
131+
/**********************************************************************
132+
/* Polymorphic handling tests
133+
/**********************************************************************
134+
*/
135+
136+
137+
public void testPolymorphicXMLGregorianCalendar() throws Exception
138+
{
139+
XMLGregorianCalendar cal = DatatypeFactory.newInstance().newXMLGregorianCalendar
140+
(1974, 10, 10, 18, 15, 17, 123, 0);
141+
String json = POLY_MAPPER.writeValueAsString(cal);
142+
Object result = POLY_MAPPER.readValue(json, Object.class);
143+
if (!(result instanceof XMLGregorianCalendar)) {
144+
fail("Expected a `XMLGregorianCalendar`, got: "+result.getClass());
145+
}
146+
assertEquals(cal, result);
147+
}
123148
}

0 commit comments

Comments
 (0)