dcompiled
dcompiled

Reputation: 4832

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

Given class:

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

And the following yaml file:

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

Using Jackson I want to deserialize this into a Map<String, Widget> where the widget name field is set to the corresponding map key. The following snippet works but has the downside of preventing use of immutable object types such as lombok @Value. Another inelegant solution I considered was creating a separate immutable WidgetWithName class that is constructed after jackson deserialization. If someone can propose a better approach, that would be of interest.



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
}

Upvotes: 1

Views: 883

Answers (1)

flyx
flyx

Reputation: 39638

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.

With SnakeYAML, you could theoretically implement this with custom constructors, but it would need a lot of knowledge about the deserialization process because YAML is not designed to merge nodes on different levels into one value.

Frankly, having a separate class is by far the simplest and best maintainable solution. A separate class named WidgetBuilder, with only the price field and a function Widget finish(String name) would allow you to

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

which seems elegant enough. (You can collect to a list instead if you don't need the map anymore.)

Upvotes: 2

Related Questions