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:
@@ -217,7 +240,17 @@ public void testSerialization() throws Exception
217
240
assertEquals ("{\" @type\" :\" typeB\" ,\" b\" :1}" , mapper .writeValueAsString (bean ));
218
241
219
242
// and default name ought to be simple class name; with context
220
- assertEquals ("{\" @type\" :\" TestSubtypes$SubD\" ,\" d\" :0}" , mapper .writeValueAsString (new SubD ()));
243
+ assertEquals ("{\" @type\" :\" TestSubtypes$SubD\" ,\" d\" :0}" , mapper .writeValueAsString (new SubD ()));
244
+ }
245
+
246
+ public void testSerializationWithDuplicateRegisteredSubtypes () throws Exception {
247
+ ObjectMapper mapper = new ObjectMapper ();
248
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub1" ));
249
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub2" ));
250
+
251
+ // the first registered type name is used for serialization
252
+ Sub sub = new Sub (15 );
253
+ assertEquals ("{\" #type\" :\" sub1\" ,\" a\" :15}" , mapper .writeValueAsString (sub ));
221
254
}
222
255
223
256
public void testDeserializationNonNamed () throws Exception
@@ -247,6 +280,28 @@ public void testDeserializatioNamed() throws Exception
247
280
assertEquals (-4 , ((SubD ) bean ).d );
248
281
}
249
282
283
+ public void testDeserializationWithDuplicateRegisteredSubtypes ()
284
+ throws Exception {
285
+ ObjectMapper mapper = new ObjectMapper ();
286
+
287
+ // We can register the same class with different names
288
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub1" ));
289
+ mapper .registerSubtypes (new NamedType (Sub .class , "sub2" ));
290
+
291
+ // fields of a POJO will be deserialized correctly according to their field name
292
+ POJOWrapper pojoWrapper = mapper .readValue ("{\" sub1\" :{\" #type\" :\" sub1\" ,\" a\" :10},\" sub2\" :{\" #type\" :\" sub2\" ,\" a\" :50}}" , POJOWrapper .class );
293
+ assertEquals (10 , pojoWrapper .sub1 .a );
294
+ assertEquals (50 , pojoWrapper .sub2 .a );
295
+
296
+ // Instances of the same object can be deserialized with multiple names
297
+ SuperTypeWithoutDefault sub1 = mapper .readValue ("{\" #type\" :\" sub1\" , \" a\" :20}" , SuperTypeWithoutDefault .class );
298
+ assertSame (Sub .class , sub1 .getClass ());
299
+ assertEquals (20 , ((Sub ) sub1 ).a );
300
+ SuperTypeWithoutDefault sub2 = mapper .readValue ("{\" #type\" :\" sub2\" , \" a\" :30}" , SuperTypeWithoutDefault .class );
301
+ assertSame (Sub .class , sub2 .getClass ());
302
+ assertEquals (30 , ((Sub ) sub2 ).a );
303
+ }
304
+
250
305
// Trying to reproduce [JACKSON-366]
251
306
public void testEmptyBean () throws Exception
252
307
{
@@ -295,7 +350,7 @@ public void testDefaultImpl() throws Exception
295
350
public void testDefaultImplViaModule () throws Exception
296
351
{
297
352
final String JSON = "{\" a\" :123}" ;
298
-
353
+
299
354
// first: without registration etc, epic fail:
300
355
try {
301
356
MAPPER .readValue (JSON , SuperTypeWithoutDefault .class );
@@ -317,7 +372,7 @@ public void testDefaultImplViaModule() throws Exception
317
372
bean = mapper .readValue ("{\" #type\" :\" foobar\" }" , SuperTypeWithoutDefault .class );
318
373
assertEquals (DefaultImpl505 .class , bean .getClass ());
319
374
assertEquals (0 , ((DefaultImpl505 ) bean ).a );
320
-
375
+
321
376
}
322
377
323
378
public void testErrorMessage () throws Exception {
@@ -361,7 +416,7 @@ public void testSubclassLimits() throws Exception
361
416
public void testIssue1125NonDefault () throws Exception
362
417
{
363
418
String json = MAPPER .writeValueAsString (new Issue1125Wrapper (new Impl1125 (1 , 2 , 3 )));
364
-
419
+
365
420
Issue1125Wrapper result = MAPPER .readValue (json , Issue1125Wrapper .class );
366
421
assertNotNull (result .value );
367
422
assertEquals (Impl1125 .class , result .value .getClass ());
0 commit comments