简体   繁体   English

如何使用Jackson反序列化将每个映射表项的键注入相应的值对象?

[英]How to inject the key of each map entry into the corresponding value object with Jackson deserialization?

I have the following json object. 我有以下json对象。

{
  "items": {
    "item-1": {"type":"A", "desc": "blabla"},
    "item-2": {"type":"B", "desc": "blabla"},
    ...
  }
}

and I want to map this json object to the following java object. 我想将此json对象映射到以下java对象。

public class MyObject {
  private final Map<String,Item> items;

  @JsonCreator
  public MyObject(@JsonProperty Map<String,Item> items) { ... }
  ...
}

class Item {
  private final string id;             <-- ideally could be initialized by the corresponding key in the map
  private final String type;
  private final String desc;

  public Item(@JsonProperty String id, @JsonProperty String type, @JsonProperty String desc) { ... }
}

The deserialization works only when I provide the following json object. 反序列化仅在我提供以下json对象时才起作用。

{
  "items": {
    "item-1": {"id":"item-1", "type":"A", "desc": "blabla"},
    "item-2": {"id":"item-2", "type":"B", "desc": "blabla"},
    ...
  }
}

That's not ideal (ie: redundancy -> error prone). 这并不理想(即:冗余 - >容易出错)。

Is there a jackson annotation to solve this common pattern, or some other way? 是否有杰克逊注释来解决这种常见模式或其他方式? I failed to find something like @JsonProperty(useKeyMap=true) . 我找不到类似@JsonProperty(useKeyMap=true)东西@JsonProperty(useKeyMap=true)

Update: I'm not interested by a solution where the id argument of the constructor is initialized to null. 更新:我对构造函数的id参数初始化为null的解决方案不感兴趣。

I have tried your example you need to put @Json creator annotation on your Items class constructor as well.

Below is the modified code.

class Item {

    private final String id;

    private final String type;

    private final String desc;

    @JsonCreator
    public Item( @JsonProperty("id")String id,   @JsonProperty("type")String type,  @JsonProperty("desc")String desc) {
        this.id = id;
        this.type = type;
        this.desc = desc;
    }
}

class MyObject {
    private final Map<String,Item> items;

    @JsonCreator
    public MyObject(@JsonProperty("items") Map<String, Item> items) {
        this.items = items;
    }

It deserialises the json and if you will not provide the value of id then default it would be null. 它反序列化json,如果你不提供id的值,那么默认它将为null。

I have found a solution for this, involving a custom Deserializer. 我找到了一个解决方案,涉及一个自定义反序列化器。 There is no real magic here (no handy annotation), but perhaps it will help. 这里没有真正的魔法(没有方便的注释),但也许它会有所帮助。

@Test
public void test() throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();

    Data data = mapper.readValue("{\"users\": {\"John\": {\"id\": 20}, \"Pete\": {\"id\": 30}}}", Data.class);

    assertEquals(20, data.users.get("John").id);
    assertEquals(30, data.users.get("Pete").id);
    assertEquals("John", data.users.get("John").name);
    assertEquals("Pete", data.users.get("Pete").name);
}

public static class Data {
    @JsonDeserialize(contentUsing = Deser.class)
    public Map<String, User> users;
}

public static class User {
    public String name;
    public int id;
}

public static class Deser extends JsonDeserializer<User> {

    @Override
    public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String name = ctxt.getParser().getCurrentName();

        User user = p.readValueAs(User.class);

        user.name = name;   // Fills the key in the value object!

        return user;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM