【问题标题】:Jackson deserialize JSON object field into single list propertyJackson 将 JSON 对象字段反序列化为单个列表属性
【发布时间】:2013-09-09 23:22:05
【问题描述】:

我只是想知道,给定一个 pojo:

public class MyProfileDto {
    private List<String> skills;
    //mutators; getSkills; setSkills + bunch of other fields
}

技能领域的 JSON:

"skills":{
 "values":[
  {
     "id":14,
     "skill":{
      "name":"C++"
     }
  },
  {
     "id":15,
     "skill":{
      "name":"Java"
     }
  }
 ],
 "_total":2
}

有什么方法可以使用 Jackson 将技能/值/技能/名称字段(即“Java”、“C++”)放入目标 Dto 的字符串列表而不为整个 Dto 创建自定义反序列化器?它有很多字段,所以如果可能的话,理想的解决方案是为一个字段添加一些自定义注释或反序列化器??

【问题讨论】:

  • 这是不可能的。想想看,哪些元素实际上会被用作List 中的String 值?
  • 我在想 Xpath 或一些谓词解决方案,它可以迭代每个值并检索它的“技能”对象的“名称”值并收集。在自定义反序列化器中,我将检索并遍历每个 JsonNodes 并以列表形式返回
  • 我相信有一些 JsonPath 样式库可以做到这一点,但杰克逊没有,而且可能没有一个注释。
  • 出于好奇,可以在一个属性上创建自定义反序列化吗?我想这会解决问题
  • 是的,你可以。沿着一条小路往前走,直到找到您想要的房产并将其添加到列表中。

标签: java json jackson


【解决方案1】:

Jackson 不包含任何 XPath 功能,但您可以为每个属性定义转换器。 Jackson 将使用此转换器将输入类型转换为您需要的输出类型。在您的示例中,输入类型为Map&lt;String, Object&gt;,输出类型为List&lt;String&gt;。可能这不是我们可以使用的最简单和最好的解决方案,但它允许我们只为一个属性定义转换器,而无需为整个实体定义反序列化器。

你的 POJO 类:

class MyProfileDto {

    @JsonDeserialize(converter = SkillConverter.class)
    private List<String> skills;

    public List<String> getSkills() {
        return skills;
    }

    public void setSkills(List<String> skills) {
        this.skills = skills;
    }
}

List&lt;String&gt; skills; 属性的转换器:

class SkillConverter implements Converter<Map<String, Object>, List<String>> {

    @SuppressWarnings("unchecked")
    public List<String> convert(Map<String, Object> value) {
        Object values = value.get("values");
        if (values == null || !(values instanceof List)) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<String>();
        for (Object item : (List<Object>) values) {
            Map<String, Object> mapItem = (Map<String, Object>) item;
            Map<String, Object> skillMap = (Map<String, Object>) mapItem.get("skill");
            if (skillMap == null) {
                continue;
            }

            result.add(skillMap.get("name").toString());
        }

        return result;
    }

    public JavaType getInputType(TypeFactory typeFactory) {
        return typeFactory.constructMapLikeType(Map.class, String.class, Object.class);
    }

    public JavaType getOutputType(TypeFactory typeFactory) {
        return typeFactory.constructCollectionLikeType(List.class, String.class);
    }
}

以及示例用法:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.Converter;

public class JacksonProgram {

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        MyProfileDto dto = mapper.readValue(new File("/x/json"), MyProfileDto.class);

        System.out.println(dto.getSkills());
    }
}

上面的程序打印:

[C++, Java]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2012-08-19
    • 2011-12-21
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    相关资源
    最近更新 更多