11package  com .fasterxml .jackson .databind .jsontype ;
22
3+ import  java .util .ArrayList ;
34import  java .util .List ;
45import  java .util .Map ;
56
1314import  com .fasterxml .jackson .databind .ObjectMapper ;
1415import  com .fasterxml .jackson .databind .exc .InvalidDefinitionException ;
1516import  com .fasterxml .jackson .databind .exc .InvalidTypeIdException ;
17+ import  com .fasterxml .jackson .databind .exc .UnrecognizedPropertyException ;
1618import  com .fasterxml .jackson .databind .json .JsonMapper ;
1719import  com .fasterxml .jackson .databind .type .TypeFactory ;
1820
@@ -210,9 +212,33 @@ public void testAmbiguousClasses() throws Exception {
210212    }
211213  }
212214
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+ 
213239  public  void  testAmbiguousProperties () throws  Exception  {
214240    try  {
215-       /*Cat  cat =*/  MAPPER .readValue (ambiguousCatJson , Cat .class );
241+       /*Feline  cat =*/  MAPPER .readValue (ambiguousCatJson , Feline .class );
216242      fail ("Should not get here" );
217243    } catch  (InvalidTypeIdException  e ) {
218244        verifyException (e , "Cannot deduce unique subtype" );
@@ -225,7 +251,7 @@ public void testFailOnInvalidSubtype() throws Exception {
225251      .disable (DeserializationFeature .FAIL_ON_INVALID_SUBTYPE )
226252      .build ();
227253    // When: 
228-     Cat  cat  = mapper .readValue (ambiguousCatJson , Cat .class );
254+     Feline  cat  = mapper .readValue (ambiguousCatJson , Feline .class );
229255    // Then: 
230256    assertNull (cat );
231257  }
@@ -269,4 +295,99 @@ public void testListSerialization() throws Exception {
269295    // Then: 
270296    assertEquals (arrayOfCatsJson , json );
271297  }
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+   }
272393}
0 commit comments