【问题标题】:Jackson custom deserializer String to List, and remove \r\nJackson 自定义反序列化器字符串到列表,并删除 \r\n
【发布时间】:2014-02-25 20:28:00
【问题描述】:

我收到以下 JSON 作为来自服务的响应。我正在使用 Spring RestTemplate 调用服务,该服务还将 JSON 反序列化回对象。我正在尝试将其反序列化为一个除了其他字段之外还有一个列表的对象。反序列化时出现以下错误:

Can not instantiate value of type [simple type, class com.org.EmployeeInfo] from String value; no single-String constructor/factory method.

以下是我要反序列化的 JSON:

{
    "employees": {       
        "employeeInfo": [
            "{\r\n  \"id\": \"123\",\r\n  \"group\": \"MARKETING\",\r\n  \"role\": \"MANAGER\",\r\n}",
            "{\r\n  \"id\": \"256\",\r\n  \"group\": \"IT\",\r\n  \"role\": \"DIRECTOR\",\r\n}",
            "{\r\n  \"id\": \"789\",\r\n  \"group\": \"SALES\",\r\n  \"role\": \"CEO\",\r\n}"
        ]
    },
    "status": "EMPLOYED",
    "somethingElse": {
        "something": []
    }
}

如果我尝试将响应映射到的对象中有List<EmployeeInfo>,则默认反序列化器会失败,但如果我使用List<String>String[],它会起作用。这是因为 JSON 中的双引号(我说的是 "{\r\n) 使其被视为字符串

我打算编写一个自定义反序列化器,将其反序列化为具有 List 的对象,并删除作为响应的一部分的 \r\n。我怎样才能做到这一点?感谢任何回复。

这是我的 POJO:

public class Response {
    private Employees employees;
    private String status;
    private SomethingElse somethingElse; 

   // getters, setters
}

public class Employees {
    List<EmployeeInfo> employeeInfo;
    // getters, setters
}

public class EmployeeInfo
{
   private String id, group, role;
   // getters, setters 
}

谢谢

【问题讨论】:

  • 你有一个 JSON 对象。这不能反序列化为List。请澄清您要做什么。你只得到employeeInfo吗?
  • 我收到了上述 json 作为来自服务的响应。我正在使用 Spring RestTemplate 调用服务,该服务还将 JSON 反序列化回对象。我试图将它反序列化为一个除了其他字段之外还有一个 List 的对象。反序列化时出现以下错误:无法从字符串值实例化类型 [简单类型,类 com.org.EmployeeInfo] 的值;没有单字符串构造函数/工厂方法
  • 用我的 POJO 更新了问题

标签: json spring jackson


【解决方案1】:

我通过以下方式解决了这个问题(部分逻辑需​​要优化)

public class EmployeeInfoJsonDeserializer extends JsonDeserializer<List<EmployeeInfo>> {

    @Override
    public List<EmployeeInfo> deserialize(final JsonParser jp, final DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {

        final ObjectMapper mapper = (ObjectMapper) jp.getCodec();

        final JsonNode node = (JsonNode) mapper.readTree(jp);

        // TODO - Write the following logic in a better way
        String toStr = node.toString();
        toStr = StringUtils.replace(toStr, "\"{", "{");
        toStr = StringUtils.replace(toStr, "}\"", "}");
        toStr = StringUtils.remove(toStr, "\\r\\n");
        toStr = StringUtils.remove(toStr, "\\");

        final JsonNode newNode = mapper.readTree(toStr);

        final EmployeeInfo[] empInfo = mapper.convertValue(newNode, EmployeeInfo[].class);

        return Arrays.asList(empInfo);
    }
}

在 Pojo 中:

public class Employees {
       List<EmployeeInfo> employeeInfo;

       public List<EmployeeInfo> getEmployeeInfo() {
            return employeeInfo;
       }

       @JsonDeserialize(using = EmployeeInfoJsonDeserializer .class)
       public void setEmployeeInfo(final List<EmployeeInfo> employeeInfo) {
            this.employeeInfo= employeeInfo;
       }
}

【讨论】:

    【解决方案2】:

    那个 JSON 是不可解析的,因为它是无效的,即使你有一个自定义的反序列化器,你也不能反序列化它。

    无论如何,一个自定义的反序列化器示例(不起作用,仅用于学习目的)

    public class EmployeeInfoDeSerializer extends JsonDeserializer<List<EmployeeInfo>> {
    
        @Override
        public List<EmployeeInfo> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    
            // for learning purpouses only, does not work
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    
            List<EmployeeInfo> employeeInfos = new ArrayList<>();
    
            while (jp.nextToken() != JsonToken.END_OBJECT) {
    
                if (jp.getCurrentToken() != JsonToken.END_ARRAY) {
    
                    JsonParser jParser = mapper.getJsonFactory().createJsonParser(jp.getText());
                    employeeInfos.add(jParser.readValueAs(EmployeeInfo.class));
                }
            }
            return employeeInfos;
        }
    }
    

    在您的员工类中

    public class Employees {
    
        @JsonDeserialize(using=EmployeeInfoDeSerializer.class)
        private List<EmployeeInfo> employeeInfo;
    
        public List<EmployeeInfo> getEmployeeInfo() {
            return employeeInfo;
        }
    
        public void setEmployeeInfo(List<EmployeeInfo> employeeInfo) {
            this.employeeInfo = employeeInfo;
        }
    
    
    }
    

    【讨论】:

    • 这就是为什么我询问删除 /r/n 并清理解串器中的 json 的原因,我尝试了一种可行的解决方法。感谢您的评论
    猜你喜欢
    • 2023-03-22
    • 2016-02-12
    • 2016-02-13
    • 2011-04-12
    • 2020-05-20
    • 2019-08-10
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    相关资源
    最近更新 更多