【问题标题】:Deserialize JSON array into Map using Jackson in Java使用Java中的Jackson将JSON数组反序列化为Map
【发布时间】:2014-08-22 11:40:17
【问题描述】:

我正在使用 fasterXML 的 Jackson (v2.3.3) 库来反序列化和序列化自定义类。类定义如下:

public class Person {

  private String name;
  private Map<String, Person> children;

  // lots of other fields of different types with no issues
}

映射children 的键是name 字段。我以 JSON 格式接收数据,每个 person 对象的结构如下(我省略了其他字段):

{"name":"Bob", "children":[{"name":"Jimmmy"},{"name":"Judy"}]}

(许多字段如children是可选的,为null时不序列化)

到目前为止,我一直将孩子存储在 List&lt;Person&gt; 中,没有任何问题,但是许多新用例需要访问名称集或使用其名称作为键的特定人员。这就是为什么我决定使用地图来存储它们。

经过一番研究,我认为最好的方法是使用注解@JsonDeserialize@JsonSerialize 分别带有JsonDeserializerJsonSerializer 作为字段children 的参数:

public class Person {

  private String id;

  @JsonSerialize(using=MySerializer.class)
  @JsonDeserialize(using=MyDeserializer.class)
  private Map<String, Person> friends;

  // lots of other fields
}

我的问题是:这样的 JsonSerializer/JsonDeserializer 是否存在,如果不存在,我该如何定义?


编辑:我已经开始实现自定义反序列化器,但我得到了这个异常:

com.fasterxml.jackson.databind.JsonMappingException: Class has no default (no arg) constructor

这很奇怪,因为我定义了一个默认构造函数。这是我的自定义反序列化器:

public class MyDeserializer extends JsonDeserializer<Map<String, Person>> {

    public MyDeserializer() {
    }

    @Override
    public Map<String, Person> deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
      JsonNode personsNodeArray = jp.getCodec().readTree(jp);
      Map<String, Person> newChildren = null;
      if (personsNodeArray.isArray() && personsNodeArray.size() > 0) {
        newChildren = new HashMap<String, Person>();
        for (JsonNode personNode : personsNodeArray) {
          String id = personNode.get("name").asText();
          // jsonMapper is a default ObjectMapper
          newChildren.put(id, jsonMapper.readValue(personNode.toString(), Person.class));
        }
      }
      return newChildren;
    }
  }

【问题讨论】:

    标签: serialization map jackson deserialization arrays


    【解决方案1】:

    您还可以考虑将儿童信息读取为人员集合,然后将其转换为地图。您可以定义一个 setter 方法(或构造函数参数)来接受 List&lt;Person&gt;,然后将每个元素放入 Map&lt;String, Person&gt; children 字段中。这将避免自定义序列化的不必要的复杂性。

    这是一个例子:

    public class JacksonChildren {
        public static final String JSON = "{\"name\":\"Bob\", \"children\":[{\"name\":\"Jimmmy\"}," +
                "{\"name\":\"Judy\"}]}";
    
        public static class Person {
            public String name;
            private Map<String, Person> children = new HashMap<>();
    
            public void setChildren(final List<Person> children) {
                for (Person p : children) {
                    this.children.put(p.name, p);
                }
            }
    
            @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", children=" + children +
                        '}';
            }
        }
    
        public static void main(String[] args) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            System.out.println(mapper.readValue(JSON, Person.class));
        }
    
    }
    

    输出:

    Person{name='Bob', children={Judy=Person{name='Judy', children={}}, Jimmmy=Person{name='Jimmmy', children={}}}}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      • 2018-06-02
      • 1970-01-01
      相关资源
      最近更新 更多