2017-04-05 51 views
0

我在我的應用程序中使用了Jackson的de/serialization。Fallback類<?> for mapper.readValue

我有一種情況,我需要將JSON字符串轉換爲我的3個類中的一個。如果字符串不能轉換爲3類中的任何一類,則認爲它是無法識別的情況。

但是,如果json字符串的架構和mapper.readValue(jsonString,MyClass1.class)中提供的類不匹配,則會拋出UnrecognizedPropertyException

目前我正在使用類似下面的東西,但它似乎很雜亂。

try { 
    obj = mapper.readValue(jsonString, MyClass1.class);    
} catch (UnrecognizedPropertyException e1) { 
    try { 
     obj = mapper.readValue(jsonString, MyClass2.class); 
    } catch (UnrecognizedPropertyException e2) { 
     try { 
      obj = mapper.readValue(jsonString, MyClass3.class); 
     } catch (Exception e) { 
      //handle unrecognized string 
     } 
    } catch (Exception e) { 
     //handle unrecognized string 
    } 
} catch (Exception e) { 
    //handle unrecognized string 
} 

這是它需要怎麼做或者是否有其他的選擇?有什麼辦法可以配置mapper返回null在無法識別的屬性的情況下,因爲這將導致創建一個簡單的系列if塊而不是嵌套try-catch塊?

回答

1

你可以試試這個方法來做反序列化的事情。這將在UnrecognizedPropertyException返回null

private <T> T deserialize(ObjectMapper mapper, Class<T> type, String jsonString) { 
     T t = null; 
     try { 
      t = mapper.readValue(jsonString, type); 
     } catch (UnrecognizedPropertyException e) { 
      //handle unrecognized string 
     }catch (IOException e) { 
      //handle under errors 
     } 
     return t; 
    } 
+0

謝謝你的回答。但似乎忽略未知屬性的配置只是通過'Class '創建一個提供的類的空實例,並使用默認值,而不是創建類的null實例。希望這個解釋清楚。 –

+1

我已經更新了我的答案,您可以創建一個通用的方法來做這種事情。 –

0

如果jsonString由您生成,可以考慮添加type info,然後用它來轉換反序列化對象。您可以參考this post瞭解如何操作。

如果jsonString由您無法控制的其他服務生成,那麼您無法獲得任何類型信息,因此您只能一個接一個地嘗試,@Sachin Gupta的答案將是一個不錯的選擇。

我想提供一個額外的選項:定義一​​個all-in-one實體包括MyClass1MyClass2MyClass3各個領域,使MyClass1MyClass2MyClass3分開包裝,只露出每個相關領域。代碼如下:

AllInOne

public class AllInOne { 
    protected String a; 
    protected String b; 
    protected String c; 

    public A asA() { 
     return new A(this); 
    } 

    public B asB() { 
     return new B(this); 
    } 

    public C asC() { 
     return new C(this); 
    } 
} 

A

public class A { 
    private AllInOne allInOne; 

    public A(AllInOne allInOne) { 
     this.allInOne = allInOne; 
    } 

    public String getA() { 
     return allInOne.a; 
    } 
} 

B

public class B { 
    private AllInOne allInOne; 

    public B(AllInOne allInOne) { 
     this.allInOne = allInOne; 
    } 

    public String getB() { 
     return allInOne.b; 
    } 
} 

C

public class C { 
    private AllInOne allInOne; 

    public C(AllInOne allInOne) { 
     this.allInOne = allInOne; 
    } 

    public String getC() { 
     return allInOne.c; 
    } 
} 

測試代碼:

public class Main { 
    public static void main(String[] args) throws IOException { 
     ObjectMapper om = new ObjectMapper(); 
     om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); 

     String jsonA = "{\"a\":\"a value\"}"; 
     String jsonB = "{\"b\":\"b value\"}"; 
     String jsonC = "{\"c\":\"c value\"}"; 

     needTypeA(om.readValue(jsonA, AllInOne.class).asA()); 
     needTypeB(om.readValue(jsonB, AllInOne.class).asB()); 
     needTypeC(om.readValue(jsonC, AllInOne.class).asC()); 
    } 

    private static void needTypeA(A a) { 
     System.out.println(a.getA()); 
    } 

    private static void needTypeB(B b) { 
     System.out.println(b.getB()); 
    } 

    private static void needTypeC(C c) { 
     System.out.println(c.getC()); 
    } 
} 

有了實施這樣的,我們在消除反序列化步驟中的特定類型的信息,並把它帶回來,在我們真正需要/使用它的那一刻。正如你所看到的,沒有太多額外的代碼,因爲我們實際上只是將所有字段聲明放在一起,並添加了幾個方法。

注:

  • AllInOne聲明字段爲protected,把所有POJO類在同一個包將使ABC能夠直接訪問它們,而不是外部的其他類。
  • 設置om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);,使傑克遜的field反序列化,這樣我們就可以從AllInOne
  • 刪除重複settergetter如果你需要知道是什麼類型的信息,您可以添加方法,如isAAllInOne基礎上的字段信息
0

如果json包含一些定義屬性,那麼您可以嘗試使用@JsonTypeInfo@JsonSubTypes。類MyClass1, ...必須實現此接口。我也不記得如何將未知的實現映射爲null。

@JsonTypeInfo(
     use = JsonTypeInfo.Id.NAME, 
     include = JsonTypeInfo.As.EXISTING_PROPERTY, // level of define property 
     property = <property_name>, 
     visible = true, 
     defaultImpl = NoClass.class) 
@JsonSubTypes({@JsonSubTypes.Type(value = <interface-impl>.class, name = <property_value>)}) 
private <interface> value; 
// getters and setters 
相關問題