2017-09-25 32 views
0

我需要將JsonArray反序列化爲布爾值。如果數組存在且不爲空,則該值應設置爲「true」。 問題是,我的自定義反序列化器在功能上打破了其餘字段的反序列化 - 它們被設置爲null。Jackson定製解串器打破其他字段的反序列化

對象:

private static class TestObject { 
    private String name; 

    @JsonProperty("arr") 
    @JsonDeserialize(using = Deserializer.class) 
    private Boolean exists = null; 

    private Integer logins; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Boolean getExists() { 
     return exists; 
    } 

    public void setExists(boolean exists) { 
     this.exists = exists; 
    } 

    public Integer getLogins() { 
     return logins; 
    } 

    public void setLogins(Integer logins) { 
     this.logins = logins; 
    } 

    @Override 
    public String toString() { 
     return "TestObject{" + 
       "name='" + name + '\'' + 
       ", exists=" + exists + 
       ", logins=" + logins + 
       '}'; 
    } 
} 

解串器:

public class Deserializer extends JsonDeserializer<Boolean> { 
    @Override 
    public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
     if (jp.getCurrentToken() == JsonToken.START_ARRAY) { 
      return true; 
     } 
     return false; 
    } 
} 

測試

@Test 
public void test() throws JsonParseException, IOException { 
    Boolean result = deserialize(); 
} 

private Boolean deserialize() throws IOException, JsonParseException, 
     JsonProcessingException { 
    TestObject testObject = mapper.readValue("{\n" + 
        " \"arr\": [\n" + 
        "  {\"value\": \"New\"}\n" + 
        " ],\n" + 
        " \"name\": \"name\",\n" + 
        " \"logins\": 36" + 
        "}", 
        TestObject.class); 

    System.out.println(testObject.toString()); 

    return testObject.getExists(); 
} 

如果我刪除了 「ARR」 陣列或將其移動到JSON,底部一切都很好。如果我把它留在頂部 - TestObject{name='null', exists=true, logins=null}

還有類似的問題(Jackson Custom Deserializer breaks default ones),但不幸的是它沒有答案。 因爲當我重新排列Json時,代碼可以正常工作,所以它看起來並不像自定義反序列化器用於所有字段,而是Jackson在執行自定義反序列化器時停止反序列化。

+1

我的建議是不要將數組反序列化爲布爾值。將數組反序列化爲一個數組/列表/集合並使'getExists'返回'arr!= null'或其他類型。 – Paul

+0

@Paul這真的有用,感謝這個想法,不知何故,我沒有想到這一點。問題是它看起來有點醜陋和晦澀,但如果沒有其他辦法,我會這樣做。 –

+0

有時,你必須選擇兩個醜陋的解決方案的漂亮:)我很高興我可以幫助...我會讓我的評論一個答案。 – Paul

回答

1

你解串器可能不感興趣的數組的內容但仍然必須推進解析器上的讀取標記。

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    JsonNode node = jp.getCodec().readTree(jp); 
    return node.size() != 0; 
} 

決定集合的大小,而不是在一個集合的存在

你可以根據集合的大小讀取arr值一次,並決定所有這一切都是必需的,因爲您的字符串化對象包含一個ARR或從未執行Deserializer.deserialize()。在這種情況下,物業exist將爲null。所以唯一可能的語義來表示不存在是一個空集合。

只是爲了好奇,我嘗試了第二種更明確的方式來保持解析器正常運行。對於現實世界使用上述版本是絕對可取的。

@Override 
public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException { 
    if (jp.currentToken() == JsonToken.START_ARRAY) { 
     jp.nextToken(); 
     int recursionLevel = 1; 
     while(recursionLevel > 0) { 
      switch (jp.currentToken()) { 
       case START_ARRAY: 
        // just in case of nested arrays 
        recursionLevel++; 
        break; 
       case END_ARRAY: 
        recursionLevel--; 
        break; 
      } 
      jp.nextToken(); 
     } 
     return true; 
    } 
    return false; 
} 
+0

這是適當的解決方案。 'JsonDeserializer' javadoc提到你必須在從解串器返回之前將讀標記移動到下一個元素,以便Jackson可以開始處理下一個元素。 在我的情況下,它是一個數組,所以移動一次,就像我嘗試的那樣,還不夠,在達到'END_ARRAY'之前,您必須多次移動它。 'readTree',據我可以告訴從javadoc,讀取整個數組,建立一棵樹,並提高閱讀標記在一個包。 –

1

我的建議是不要將數組反序列化爲布爾值。將數組反序列化爲一個數組/列表/集合,並且有getExists返回arr != null或其他。

例如,如果JSON你要反序列化看起來是這樣的:

{ 
    "arr": [{"value": "New"}], 
    "name": "name", 
    "logins": 36 
} 

這樣寫你的實體:

private static class TestObject 
{ 
    private List<Map<String, String>> arr; 

    // other getters/setters removed for brevity 

    public boolean getExists() 
    { 
    return arr !=null && !arr.isEmpty(); 
    } 
} 
0

其實還有第三個辦法做到這一點,適合我的情況 - JsonArray總是包含當它不缺,所以我需要的是適當超前的讀取標記,然後返回true至少一個元素:

if (jp.getCurrentToken().equals(JsonToken.START_ARRAY)) { 
    while (!jp.getCurrentToken().equals(JsonToken.END_ARRAY)){ 
     jp.nextToken(); 
    } 
} 
return true; 

除非你不需要數組的內容進行一些額外的工作,只是移動標記比readTree快幾毫秒。

相關問題