簡體   English   中英

Deserialize YAML map of POJOs with Jackson where Map keys are an object field

[英]Deserialize YAML map of POJOs with Jackson where Map keys are an object field

給定 class:

@Data
class Widget {
  String name;
  int price;
}

以及以下 yaml 文件:

Widget1:
  price: 5
Widget2:
  price: 6
Widget3:
  price: 7

使用 Jackson 我想將其反序列化為Map<String, Widget> ,其中小部件名稱字段設置為相應的 map 鍵。 以下代碼段有效,但缺點是阻止使用不可變的 object 類型,例如@Value 我考慮的另一個不優雅的解決方案是創建一個單獨的不可變WidgetWithName class,它是在 jackson 反序列化之后構建的。 如果有人可以提出更好的方法,那將很有趣。



Map<String, Widget> getWidgets(String yaml) throws Exception {
    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    TypeFactory typeFactory = mapper.getTypeFactory();
    MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, Widget.class);

    map = mapper.readValue(yaml, mapType);
    map.forEach((k, v) -> v.setName(k); // so much for immutability
    return map
}

Jackson will not help you because it is a generalization over YAML and JSON (and XML or so I heard) and therefore provides less functionality than directly using SnakeYAML.

使用 SnakeYAML,理論上您可以使用自定義構造函數來實現這一點,但它需要大量關於反序列化過程的知識,因為 YAML 並非旨在將不同級別的節點合並為一個值。

坦率地說,擁有一個單獨的 class 是迄今為止最簡單和最好的可維護解決方案。 一個單獨的 class 名為WidgetBuilder ,只有price字段和 function Widget finish(String name)將允許您

return map.entrySet().stream().map((k, v) -> v.finish(k)).collect(
    Collectors.toMap(Widget::getName, Function.identity()));

這似乎足夠優雅。 (如果您不再需要 map,您可以收集到一個列表。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM