2017-02-13 83 views
1

給定一個具有可變屬性的JSON對象(例如標籤),它可以是原始值(例如字符串)或對象。一個假設的用例可能是一個標籤的多元化的翻譯包裝:將可變(原始/對象)JSON屬性反序列化爲與Jackson對象

{ 
    "label": "User name" 
} 

{ 
    "label": { 
     "one": "A label", 
     "other": "The labels" 
    } 
} 

的目標是把Jackson反序列化總是在Java端返回一個固定的結構。因此,如果原始值是給它總是被轉換到一定的資產(如其他)目標POJO的,即:

public class Translations { 
    @JsonDeserialize(using = PluralizedTranslationDeserializer.class) 
    public PluralizedTranslation label; 
} 

public class PluralizedTranslation { 
    public String one; 
    public String other; // used as default fields for primitive value 
} 

目前的問題是通過使用自定義JsonDeserializer,檢查是否有解決財產原始與否:

public class PluralizedTranslationDeserializer extends JsonDeserializer { 
    @Override 
    public PluralizedTranslation deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { 
     ObjectCodec oc = jsonParser.getCodec(); 
     JsonNode node = oc.readTree(jsonParser); 
     PluralizedTranslation translation; 

     if (node.isTextual()) { 
      translation = new PluralizedTranslation(); 
      translation.other = node.asText(); 
     } else { 
      translation = oc.treeToValue(node, PluralizedTranslation.class); 
     } 

     return translation; 
    } 
} 

是否有一個更優雅的方法來處理可變的JSON屬性,而不需要解碼器在節點級別上運行?

+2

這個問題沒有關於可變性。你只是有一個屬性,並想以某種方式反序列化它。 –

+0

@ Miha_x64我將屬性值描述爲可變的,因爲其值的類型具有[「責任或傾向改變」](https://en.oxforddictionaries.com/definition/mutability)。對於誤導性形容詞很抱歉,這個問題當然不是關於(Java)對象可變性的問題。 – dim

回答

2

你可以使label設置更通用,並添加一些邏輯處理這兩種情況。

public class Translations { 
    // Fields omitted. 

    @JsonProperty("label") 
    public void setLabel(Object o) { 
     if (o instanceof String) { 
      // Handle the first case 
     } else if (o instanceof Map) { 
      // Handle the second case 
     } else { 
      throw new RuntimeException("Unsupported"); 
     } 
    } 
} 

替代解決方案,哪個地方PluralizedTranslation類中的工廠方法,使Translations類的影響:

public class PluralizedTranslation { 
    public String one; 
    public String other; // used as default fields for primitive value 

    @JsonCreator 
    private PluralizedTranslation(Object obj) { 
     if (obj instanceof Map) { 
      Map map = (Map) obj; 
      one = (String) map.get("one"); 
      other = (String) map.get("other"); 
     } else if (obj instanceof String) { 
      other = (String) obj; 
     } else { 
      throw new RuntimeException("Unsupported"); 
     } 
    } 
} 

注意,構造函數可以被標記爲private以防止意外使用。

+0

感謝您的回答。的確,這個解決方案消除了「JsonDeserializer」。不幸的是,它也將'PluralizedTranslation'創建邏輯移動到POJO中。因此,它會得到一些工廠和/或ObjectMapper的依賴關係,這不是很好。此外,爲了簡單起見,我們需要添加'private'字段(爲了簡單起見,在問題中省略),我們需要爲'實例PluralizedTranslation'添加額外的檢查。總而言之,這種替代解決方案對我來說看起來不太清潔...... – dim

+0

@dim:我不能完全遵循你的反對意見,但我會盡力回答他們。在任何情況下都需要某種工廠。我認爲把它放在課堂上可以更容易理解發生的情況。我不明白需要一個'o instanceof PluralizedTranslation'。在這兩種情況下,都會創建一個'PluralizedTranslation'實例,這是該類用戶唯一需要處理的事情。我添加了另一種方法,它將「PluralizedTranslation」的創建放置在一個私有構造函數中,我發現它很優雅。 – Henrik

+0

我同意你的解決方案很容易理解。我的第一個反對意見是,'setLabel'應該能夠接受'PluralizedTranslation'(它當前會導致'RuntimeException')的一個有效實例,但這是毫不費力的事實。第二:使用ObjectMapper而不是手工映射是合理的,這意味着它必須被注入到POJO中。這是我不舒服的地方。然而,你的建議對於給定的簡單案例是有效的,但我更多地尋找一個魔術'@ JsonDefaultValue'註釋;)。 – dim