4
4
5
5
import java .util .*;
6
6
7
+ import com .fasterxml .jackson .annotation .JsonProperty ;
7
8
import com .fasterxml .jackson .annotation .JsonSubTypes ;
8
9
import com .fasterxml .jackson .annotation .JsonTypeInfo ;
9
10
import com .fasterxml .jackson .annotation .JsonTypeName ;
@@ -38,7 +39,7 @@ static class SubD extends SuperType {
38
39
// "Empty" bean
39
40
@ JsonTypeInfo (use =JsonTypeInfo .Id .NAME )
40
41
static abstract class BaseBean { }
41
-
42
+
42
43
static class EmptyBean extends BaseBean { }
43
44
44
45
static class EmptyNonFinal { }
@@ -49,7 +50,7 @@ static class PropertyBean
49
50
{
50
51
@ JsonTypeInfo (use =JsonTypeInfo .Id .NAME )
51
52
public SuperType value ;
52
-
53
+
53
54
public PropertyBean () { this (null ); }
54
55
public PropertyBean (SuperType v ) { value = v ; }
55
56
}
@@ -70,6 +71,28 @@ static class DefaultImpl505 extends SuperTypeWithoutDefault {
70
71
public int a ;
71
72
}
72
73
74
+ static class Sub extends SuperTypeWithoutDefault {
75
+ public int a ;
76
+
77
+ public Sub (){}
78
+ public Sub (int a ) {
79
+ this .a = a ;
80
+ }
81
+ }
82
+
83
+ static class POJOWrapper {
84
+ @ JsonProperty
85
+ Sub sub1 ;
86
+ @ JsonProperty
87
+ Sub sub2 ;
88
+
89
+ public POJOWrapper (){}
90
+ public POJOWrapper (Sub sub1 , Sub sub2 ) {
91
+ this .sub1 = sub1 ;
92
+ this .sub2 = sub2 ;
93
+ }
94
+ }
95
+
73
96
@ JsonTypeInfo (use =JsonTypeInfo .Id .NAME , include =As .PROPERTY , property ="type" )
74
97
@ JsonSubTypes ({ @ JsonSubTypes .Type (ImplX .class ),
75
98
@ JsonSubTypes .Type (ImplY .class ) })
@@ -118,7 +141,7 @@ static class Issue1125Wrapper {
118
141
public Issue1125Wrapper () { }
119
142
public Issue1125Wrapper (Base1125 v ) { value = v ; }
120
143
}
121
-
144
+
122
145
@ JsonTypeInfo (use =JsonTypeInfo .Id .NAME , defaultImpl =Default1125 .class )
123
146
@ JsonSubTypes ({ @ JsonSubTypes .Type (Interm1125 .class ) })
124
147
static class Base1125 {
@@ -204,7 +227,7 @@ public void testSubtypesViaModule() throws Exception
204
227
result = mapper .readValue (json , PropertyBean .class );
205
228
assertSame (SubC .class , result .value .getClass ());
206
229
}
207
-
230
+
208
231
public void testSerialization () throws Exception
209
232
{
210
233
// serialization can detect type name ok without anything extra:
@@ -216,8 +239,12 @@ public void testSerialization() throws Exception
216
239
mapper .registerSubtypes (new NamedType (SubB .class , "typeB" ));
217
240
assertEquals ("{\" @type\" :\" typeB\" ,\" b\" :1}" , mapper .writeValueAsString (bean ));
218
241
242
+ // the first registered type name is used for serialization
243
+ mapper .registerSubtypes (new NamedType (SubB .class , "ignoredOnSerialization" ));
244
+ assertEquals ("{\" @type\" :\" typeB\" ,\" b\" :1}" , mapper .writeValueAsString (bean ));
245
+
219
246
// and default name ought to be simple class name; with context
220
- assertEquals ("{\" @type\" :\" TestSubtypes$SubD\" ,\" d\" :0}" , mapper .writeValueAsString (new SubD ()));
247
+ assertEquals ("{\" @type\" :\" TestSubtypes$SubD\" ,\" d\" :0}" , mapper .writeValueAsString (new SubD ()));
221
248
}
222
249
223
250
public void testDeserializationNonNamed () throws Exception
@@ -236,6 +263,7 @@ public void testDeserializatioNamed() throws Exception
236
263
ObjectMapper mapper = new ObjectMapper ();
237
264
mapper .registerSubtypes (SubB .class );
238
265
mapper .registerSubtypes (new NamedType (SubD .class , "TypeD" ));
266
+ mapper .registerSubtypes (new NamedType (SubD .class , "typeD" ));
239
267
240
268
SuperType bean = mapper .readValue ("{\" @type\" :\" TypeB\" , \" b\" :13}" , SuperType .class );
241
269
assertSame (SubB .class , bean .getClass ());
@@ -245,6 +273,24 @@ public void testDeserializatioNamed() throws Exception
245
273
bean = mapper .readValue ("{\" @type\" :\" TypeD\" , \" d\" :-4}" , SuperType .class );
246
274
assertSame (SubD .class , bean .getClass ());
247
275
assertEquals (-4 , ((SubD ) bean ).d );
276
+
277
+ // we can register the same subtype under two names
278
+ bean = mapper .readValue ("{\" @type\" :\" typeD\" , \" d\" :-4}" , SuperType .class );
279
+ assertSame (SubD .class , bean .getClass ());
280
+ assertEquals (-4 , ((SubD ) bean ).d );
281
+
282
+ }
283
+
284
+ public void testDeserializationWithDuplicateRegisteredSubtypes ()
285
+ throws Exception {
286
+ ObjectMapper mapper = new ObjectMapper ();
287
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub1" ));
288
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub2" ));
289
+
290
+ POJOWrapper pojoWrapper = mapper .readValue ("{\" sub1\" :{\" #type\" :\" sub1\" ,\" a\" :10},\" sub2\" :{\" #type\" :\" sub2\" ,\" a\" :50}}" , POJOWrapper .class );
291
+
292
+ assertEquals (10 , pojoWrapper .sub1 .a );
293
+ assertEquals (50 , pojoWrapper .sub2 .a );
248
294
}
249
295
250
296
// Trying to reproduce [JACKSON-366]
@@ -295,7 +341,7 @@ public void testDefaultImpl() throws Exception
295
341
public void testDefaultImplViaModule () throws Exception
296
342
{
297
343
final String JSON = "{\" a\" :123}" ;
298
-
344
+
299
345
// first: without registration etc, epic fail:
300
346
try {
301
347
MAPPER .readValue (JSON , SuperTypeWithoutDefault .class );
@@ -317,7 +363,7 @@ public void testDefaultImplViaModule() throws Exception
317
363
bean = mapper .readValue ("{\" #type\" :\" foobar\" }" , SuperTypeWithoutDefault .class );
318
364
assertEquals (DefaultImpl505 .class , bean .getClass ());
319
365
assertEquals (0 , ((DefaultImpl505 ) bean ).a );
320
-
366
+
321
367
}
322
368
323
369
public void testErrorMessage () throws Exception {
@@ -361,7 +407,7 @@ public void testSubclassLimits() throws Exception
361
407
public void testIssue1125NonDefault () throws Exception
362
408
{
363
409
String json = MAPPER .writeValueAsString (new Issue1125Wrapper (new Impl1125 (1 , 2 , 3 )));
364
-
410
+
365
411
Issue1125Wrapper result = MAPPER .readValue (json , Issue1125Wrapper .class );
366
412
assertNotNull (result .value );
367
413
assertEquals (Impl1125 .class , result .value .getClass ());
@@ -374,7 +420,7 @@ public void testIssue1125NonDefault() throws Exception
374
420
public void testIssue1125WithDefault () throws Exception
375
421
{
376
422
Issue1125Wrapper result = MAPPER .readValue (aposToQuotes ("{'value':{'a':3,'def':9,'b':5}}" ),
377
- Issue1125Wrapper .class );
423
+ Issue1125Wrapper .class );
378
424
assertNotNull (result .value );
379
425
assertEquals (Default1125 .class , result .value .getClass ());
380
426
Default1125 impl = (Default1125 ) result .value ;
0 commit comments