1
1
package com .fasterxml .jackson .databind .jsontype ;
2
2
3
+ import java .util .ArrayList ;
3
4
import java .util .List ;
4
5
import java .util .Map ;
5
6
13
14
import com .fasterxml .jackson .databind .ObjectMapper ;
14
15
import com .fasterxml .jackson .databind .exc .InvalidDefinitionException ;
15
16
import com .fasterxml .jackson .databind .exc .InvalidTypeIdException ;
17
+ import com .fasterxml .jackson .databind .exc .UnrecognizedPropertyException ;
16
18
import com .fasterxml .jackson .databind .json .JsonMapper ;
17
19
import com .fasterxml .jackson .databind .type .TypeFactory ;
18
20
@@ -210,9 +212,33 @@ public void testAmbiguousClasses() throws Exception {
210
212
}
211
213
}
212
214
215
+ public void testUnrecognizedProperties () throws Exception {
216
+ try {
217
+ /*Cat cat =*/
218
+ MAPPER .readValue (ambiguousCatJson , Cat .class );
219
+ fail ("Unable to map, because there is unknown field 'age'" );
220
+ } catch (UnrecognizedPropertyException e ) {
221
+ verifyException (e , "Unrecognized field" );
222
+ }
223
+ }
224
+
225
+ public void testNotFailOnUnknownProperty () throws Exception {
226
+ // Given:
227
+ JsonMapper mapper = JsonMapper .builder ()
228
+ .disable (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES )
229
+ .build ();
230
+ // When:
231
+ Cat cat = mapper .readValue (ambiguousCatJson , Cat .class );
232
+ // Then:
233
+ // unknown proparty 'age' is ignored, and json is deserialized to Cat class
234
+ assertTrue (cat instanceof Cat );
235
+ assertSame (Cat .class , cat .getClass ());
236
+ assertEquals ("Felix" , cat .name );
237
+ }
238
+
213
239
public void testAmbiguousProperties () throws Exception {
214
240
try {
215
- /*Cat cat =*/ MAPPER .readValue (ambiguousCatJson , Cat .class );
241
+ /*Feline cat =*/ MAPPER .readValue (ambiguousCatJson , Feline .class );
216
242
fail ("Should not get here" );
217
243
} catch (InvalidTypeIdException e ) {
218
244
verifyException (e , "Cannot deduce unique subtype" );
@@ -225,7 +251,7 @@ public void testFailOnInvalidSubtype() throws Exception {
225
251
.disable (DeserializationFeature .FAIL_ON_INVALID_SUBTYPE )
226
252
.build ();
227
253
// When:
228
- Cat cat = mapper .readValue (ambiguousCatJson , Cat .class );
254
+ Feline cat = mapper .readValue (ambiguousCatJson , Feline .class );
229
255
// Then:
230
256
assertNull (cat );
231
257
}
@@ -269,4 +295,99 @@ public void testListSerialization() throws Exception {
269
295
// Then:
270
296
assertEquals (arrayOfCatsJson , json );
271
297
}
298
+
299
+ @ JsonTypeInfo (use = DEDUCTION , defaultImpl = ListOfPlaces .class )
300
+ @ JsonSubTypes ( {@ Type (ListOfPlaces .class ), @ Type (CompositePlace .class ), @ Type (Place .class )})
301
+ interface WorthSeeing {}
302
+
303
+ public static class Place implements WorthSeeing {
304
+ public String name ;
305
+ }
306
+
307
+ public static class CompositePlace extends Place implements WorthSeeing {
308
+
309
+ public Map <String , WorthSeeing > places ;
310
+ }
311
+
312
+ static class ListOfPlaces extends ArrayList <WorthSeeing > implements WorthSeeing {
313
+ }
314
+
315
+ private static final String colosseumJson = a2q ("{'name': 'The Colosseum'}" );
316
+ private static final String romanForumJson = a2q ("{'name': 'The Roman Forum'}" );
317
+ private static final String romeJson = a2q ("{'name': 'Rome', 'places': {'colosseum': " + colosseumJson + "," + "'romanForum': " + romanForumJson +"}}" );
318
+
319
+ private static final String rialtoBridgeJson = a2q ("{'name': 'Rialto Bridge'}" );
320
+ private static final String sighsBridgeJson = a2q ("{'name': 'The Bridge Of Sighs'}" );
321
+ private static final String bridgesJson = a2q ("[" + rialtoBridgeJson +"," + sighsBridgeJson +"]" );
322
+ private static final String veniceJson = a2q ("{'name': 'Venice', 'places': {'bridges': " + bridgesJson + "}}" );
323
+
324
+ private static final String alpsJson = a2q ("{'name': 'The Alps'}" );
325
+ private static final String citesJson = a2q ("[" + romeJson + "," + veniceJson + "]" );
326
+ private static final String italy = a2q ("{'name': 'Italy', 'places': {'mountains': " + alpsJson + ", 'cities': " + citesJson +"}}}" );
327
+
328
+ public void testSupertypeInferenceWhenDefaultDefined () throws Exception {
329
+ //When:
330
+ WorthSeeing worthSeeing = MAPPER .readValue (alpsJson , WorthSeeing .class );
331
+ // Then:
332
+ assertEqualsPlace ("The Alps" , worthSeeing );
333
+ }
334
+
335
+ public void testDefaultImplementation () throws Exception {
336
+ // When:
337
+ WorthSeeing worthSeeing = MAPPER .readValue (citesJson , WorthSeeing .class );
338
+ // Then:
339
+ assertCities (worthSeeing );
340
+ }
341
+
342
+ public void testCompositeInference () throws Exception {
343
+ // When:
344
+ WorthSeeing worthSeeing = MAPPER .readValue (italy , WorthSeeing .class );
345
+ // Then:
346
+ assertSame (CompositePlace .class , worthSeeing .getClass ());
347
+ CompositePlace italy = (CompositePlace ) worthSeeing ;
348
+ assertEquals ("Italy" , italy .name );
349
+ assertEquals (2 , italy .places .size ());
350
+ assertEqualsPlace ("The Alps" , italy .places .get ("mountains" ));
351
+ assertEquals (2 , italy .places .size ());
352
+ assertCities (italy .places .get ("cities" ));
353
+ }
354
+
355
+ private void assertCities (WorthSeeing worthSeeing ) {
356
+ assertSame (ListOfPlaces .class , worthSeeing .getClass ());
357
+ ListOfPlaces cities = (ListOfPlaces ) worthSeeing ;
358
+ assertEquals (2 , cities .size ());
359
+ assertRome (cities .get (0 ));
360
+ assertVenice (cities .get (1 ));
361
+ }
362
+
363
+ private void assertRome (WorthSeeing worthSeeing ) {
364
+ assertSame (CompositePlace .class , worthSeeing .getClass ());
365
+ CompositePlace rome = (CompositePlace ) worthSeeing ;
366
+ assertEquals ("Rome" , rome .name );
367
+ assertEquals (2 , rome .places .size ());
368
+ assertEqualsPlace ("The Colosseum" , rome .places .get ("colosseum" ));
369
+ assertEqualsPlace ("The Roman Forum" , rome .places .get ("romanForum" ));
370
+ }
371
+
372
+ private void assertVenice (WorthSeeing worthSeeing ) {
373
+ assertSame (CompositePlace .class , worthSeeing .getClass ());
374
+ CompositePlace venice = (CompositePlace ) worthSeeing ;
375
+ assertEquals ("Venice" , venice .name );
376
+ assertEquals (1 , venice .places .size ());
377
+ assertVeniceBridges (venice .places .get ("bridges" ));
378
+
379
+ }
380
+
381
+ private void assertVeniceBridges (WorthSeeing worthSeeing ){
382
+ assertSame (ListOfPlaces .class , worthSeeing .getClass ());
383
+ ListOfPlaces bridges = (ListOfPlaces ) worthSeeing ;
384
+ assertEqualsPlace ("Rialto Bridge" , bridges .get (0 ));
385
+ assertEqualsPlace ("The Bridge Of Sighs" , bridges .get (1 ));
386
+ }
387
+
388
+ private void assertEqualsPlace (String expectedName , WorthSeeing worthSeeing ){
389
+ assertTrue (worthSeeing instanceof Place );
390
+ assertSame (Place .class , worthSeeing .getClass ());
391
+ assertEquals (expectedName ,((Place ) worthSeeing ).name );
392
+ }
272
393
}
0 commit comments