使用 ruoyi 的框架做项目开发,在写三方接口的时候发现,获取的返回内容反序列化(JSON 格式数据解析)失败了:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "ACC" (class com.ruoyi.api.domain.DeviceYunGu), not marked as ignorable (16 known properties: "acc", "totalMileage", "speed", "imei", "direct", "lon", "isStop", "locTime", "fortify", "signalTime", "locType", "satellite", "onlineState", "lat", "signals", "electricity"])

解析代码:

        String json = "{\"errcode\":0,\"errmsg\":\"success\",\"data\":[{\"imei\":\"123\",\"onlineState\":0,\"speed\":-1,\"direct\":-1,\"lon\":-1,\"lat\":-1,\"locTime\":-1,\"locType\":-1,\"ACC\":-1,\"fortify\":-1,\"signals\":-1,\"satellite\":-1,\"signalTime\":-1,\"electricity\":-1,\"isStop\":-1,\"totalMileage\":-1}]}";

        ObjectMapper mapper = new ObjectMapper();

        try {
            ResultYunGu<List<DeviceYunGu>> resultYunGu = mapper.readValue(json,  new TypeReference<ResultYunGu<List<DeviceYunGu>>>() {});
            log.info(resultYunGu.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

可以肯定的是,返回数据里的参数字段名为 ACC,在返回对象中定义的属性也是 ACC,但在解析的时候识别成了 acc,这使得解析获取不到属性名为 ACC 的属性而报错。

百度了一下,提出的 解决方法 是添加注解或者配置项,让解析器忽略掉未知的属性,或者说未匹配到的属性。

// 第一种解决方案
// ObjectMapper对象添加
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String s = "{\"id\":1,\"name\":\"test\",\"age\":19}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
User value = mapper.readValue(s, User.class);
System.out.println(value);

// 第二种解决方案
// 在需要转化的对象的类中添加注解,注解信息如下:
@JsonIgnoreProperties(ignoreUnknown = true)
public class User
...

选择第二种方法,添加注解测试了一下,解析过程不再报错,但 ACC 属性值变成了 null。这显然达不到我想要的结果,我要的是这个属性能够正常的解析出值来。

再次百度 Jackson反序列化遇到大写字段名获取不到,得到了百度 AI 的一个示例,添加 @JsonProperty("") 注解可以指定 JSON 中的键名

import com.fasterxml.jackson.annotation.JsonProperty;
 
public class Example {
    @JsonProperty("MY_FIELD_NAME") // 指定JSON中的键名
    private String myFieldName;
 
    // 省略getter和setter方法
}

添加之后测试有效,可以获取到正确的值。浏览到 Jackson进行Json反序列化对于一个小写字母开头后跟大写字母无法识别反序列成功问题,情景几乎是相同的,作者分析了一下 Jackson 源码,还提供了另外几种解决方法:

  • 换工具,Gson,fastjson符合直觉,能填充成功(Gson这块代码非常清晰,思路符合直觉)
  • 将属性访问限制符由 private 修改为 public
  • 自己实现 get 方法

第一种换工具看着就比较麻烦(Jackson 属于 Spring web 默认使用的解析工具),没考虑。其他两种方法测试,修改访问限制符为 public 是可以的,自定义 get 方法,可能因为使用了 lombok 注解被覆盖了,没有成功。

综合来看,还是使用注解 @JsonProperty("ACC") 最方便。