当前位置: 首页 > article >正文

json报文的序列化与反序列化问题总结(对比fastjson和jackson)

一、背景

有一个http查询接口,返回json报文,然后反序列为一个ApiResult对象,最后取出对象的data字段内容,并反序列为ClassroomCopyResultNotify对象。

但是,在最后反序列化的时候,报错如下:

java.lang.IllegalArgumentException: Cannot construct instance of `com.xxx.service.dto.ClassroomCopyResultNotify` 
(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value 
('{"requestNo":"658ac2929d47479fbbe5a4a7ec86c451","newClassroomId":"FJGYYISL","sourceClassroomId":"XOJG0AOB"}')
 at [Source: UNKNOWN; line: -1, column: -1]

二、伪代码

下面贴出相关的类代码:

1、ApiResult.java

@ApiModel
@Getter
public final class ApiResult<T> {

    @ApiModelProperty(notes = "code")
    private int code;

    @ApiModelProperty(notes = "报文体")
    private T data;

    @ApiModelProperty(notes = "msg")
    private String msg;
}

2、Json报文反序列化为ApiResult对象

  • json报文:
{
    "code": 200,
    "msg": "success",
    "data": "{\"requestNo\":\"658ac2929d47479fbbe5a4a7ec86c451\",\"newClassroomId\":\"FJGYYISL\",\"sourceClassroomId\":\"XOJG0AOB\"}"
}
  • 反序列化,使用jackson框架的ObjectMapper
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

    private static ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        //忽略反序列化中的一些错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    ApiResult<?> apiResult = objectMapper.readValue(jsonStr, new TypeReference<ApiResult<?>>() {
            });

3、取出apiResult的data内容,反序列化为java对象

下面的代码是出错时的写法。

ClassroomCopyResultNotify response = objectMapper.convertValue(apiResult.getData(), ClassroomCopyResultNotify.class);

错误在于,data字段的内容,并不是一个严格意义的json字符串。它多了一个反斜杠。

在这里插入图片描述
详细的报错内容见下:


java.lang.IllegalArgumentException: Cannot construct instance of `com.xxx.service.dto.ClassroomCopyResultNotify` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"requestNo":"658ac2929d47479fbbe5a4a7ec86c451","newClassroomId":"FJGYYISL","sourceClassroomId":"XOJG0AOB"}')
 at [Source: UNKNOWN; line: -1, column: -1]
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3922)
	at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3853)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
	at sun.reflect.GeneratedMethodAccessor358.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.xxl.job.core.handler.impl.MethodJobHandler.execute(MethodJobHandler.java:29)
	at com.xxl.job.core.thread.JobThread.run(JobThread.java:152)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.xxx.service.dto.ClassroomCopyResultNotify` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"requestNo":"658ac2929d47479fbbe5a4a7ec86c451","newClassroomId":"FJGYYISL","sourceClassroomId":"XOJG0AOB"}')
 at [Source: UNKNOWN; line: -1, column: -1]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1429)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1059)
	at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
	at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3917)
	... 25 common frames omitted
  • 期望data字段的内容见下:
{
    "code": 200,
    "msg": "success",
    "data": {
        "requestNo": "658ac2929d47479fbbe5a4a7ec86c451",
        "newClassroomId": "FJGYYISL",
        "sourceClassroomId": "XOJG0AOB"
    }
}

注意: 因为Http响应报文在经过jackjson序列化的时候,data就是一个字符串,无法去掉反斜杠。

4、正确的写法应该是:

ClassroomCopyResultNotify response = JSON.parseObject(apiResult.getData().toString(), ClassroomCopyResultNotify.class);

三、完整的代码

  • ClassroomCopyResultNotify.java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ClassroomCopyResultNotify {
    private String sourceClassroomId;

    private String newClassroomId;

    private String requestNo;
}
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xhtech.service.course.interfaces.http.assembler.ApiResult;

public class JsonUtils {
    private static ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        //忽略反序列化中的一些错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static void main(String[] args) {
        ApiResult<?> apiResult = getApiResult();

        if (apiResult != null) {
            try {
                ClassroomCopyResultNotify response = JSON.parseObject(apiResult.getData().toString(), ClassroomCopyResultNotify.class);
                System.out.println("json内容反序列化后(正确的写法):" +response);
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                ClassroomCopyResultNotify response = objectMapper.convertValue(apiResult.getData(), ClassroomCopyResultNotify.class);
                System.out.println("json内容反序列化后(错误的写法):" +response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        ApiResult<?> apiResultForExpected = getApiResultForExpected();

        if (apiResultForExpected != null) {
            try {
                ClassroomCopyResultNotify response = JSON.parseObject(apiResult.getData().toString(), ClassroomCopyResultNotify.class);
                System.out.println("期望的json内容反序列化后(fastjson的写法):" +response);
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                ClassroomCopyResultNotify response = objectMapper.convertValue(apiResultForExpected.getData(), ClassroomCopyResultNotify.class);
                System.out.println("期望的json内容反序列化后(jackson的写法):" + response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static ApiResult<?> getApiResult() {
        try {
            String jsonStr = "{\n" +
                    "    \"code\": 200,\n" +
                    "    \"msg\": \"success\",\n" +
                    "    \"data\": \"{\\\"requestNo\\\":\\\"658ac2929d47479fbbe5a4a7ec86c451\\\",\\\"newClassroomId\\\":\\\"FJGYYISL\\\",\\\"sourceClassroomId\\\":\\\"XOJG0AOB\\\"}\"\n" +
                    "}";

            ApiResult<?> apiResult = objectMapper.readValue(jsonStr, new TypeReference<ApiResult<?>>() {
            });

            return apiResult;
        } catch (Exception e) {
            return null;
        }
    }

    private static ApiResult<?> getApiResultForExpected() {
        try {
            String expectedJsonStr = "{\n" +
                    "    \"data\": {\n" +
                    "        \"requestNo\": \"658ac2929d47479fbbe5a4a7ec86c451\",\n" +
                    "        \"newClassroomId\": \"FJGYYISL\",\n" +
                    "        \"sourceClassroomId\": \"XOJG0AOB\"\n" +
                    "    },\n" +
                    "    \"code\": 200,\n" +
                    "    \"msg\": \"success\"\n" +
                    "}";
            ApiResult<?> apiResult = objectMapper.readValue(expectedJsonStr, new TypeReference<ApiResult<?>>() {
            });

            return apiResult;
        } catch (Exception e) {
            return null;
        }
    }

}

  • 运行结果
json内容反序列化后(正确的写法)ClassroomCopyResultNotify(sourceClassroomId=XOJG0AOB, newClassroomId=FJGYYISL, requestNo=658ac2929d47479fbbe5a4a7ec86c451)

java.lang.IllegalArgumentException: Cannot construct instance of `com.xxx.service.dto.ClassroomCopyResultNotify` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"requestNo":"658ac2929d47479fbbe5a4a7ec86c451","newClassroomId":"FJGYYISL","sourceClassroomId":"XOJG0AOB"}')
 at [Source: UNKNOWN; line: -1, column: -1]
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3922)
	at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3853)
	at JsonUtils.main(JsonUtils.java:31)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.xxx.service.dto.ClassroomCopyResultNotify` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"requestNo":"658ac2929d47479fbbe5a4a7ec86c451","newClassroomId":"FJGYYISL","sourceClassroomId":"XOJG0AOB"}')
 at [Source: UNKNOWN; line: -1, column: -1]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1429)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1059)
	at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
	at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3917)
	... 2 more

期望的json内容反序列化后(fastjson的写法)ClassroomCopyResultNotify(sourceClassroomId=XOJG0AOB, newClassroomId=FJGYYISL, requestNo=658ac2929d47479fbbe5a4a7ec86c451)

期望的json内容反序列化后(jackson的写法)ClassroomCopyResultNotify(sourceClassroomId=XOJG0AOB, newClassroomId=FJGYYISL, requestNo=658ac2929d47479fbbe5a4a7ec86c451)

四、总结

通过上面代码的运行结果可以得知,fastjson在处理带反斜杠的json字符串时,兼容性比jackson要强。


http://www.kler.cn/a/472612.html

相关文章:

  • 用python 进行雷电接口检测
  • STM32Flash读写BUG,坑—————4字对齐
  • 从Linux本地软件存储库安装MySQL
  • HTML-多媒体标签
  • STM32之CAN通讯(十一)
  • 面试高频:一致性hash算法
  • QT鼠标、键盘事件
  • JavaAPI.02.包装类与正则表达式
  • 在vue3项目中利用自定义ref实现防抖
  • C++和Python中负数取余结果的区别
  • imageio 图片转mp4 保存mp4
  • 深度学习从入门到实战——卷积神经网络原理解析及其应用
  • js 根据条件判断样式
  • ElasticSearch内存占用率过高怎么办?
  • Java中将特征向量转换为矩阵的实现
  • CentOS 8 系统中添加 4G 大小的swap(交换空间)
  • 如何理解支持向量回归
  • 滑动变阻器的三种连接方式
  • linux中给自己编译的模块签名
  • element-ui下拉输入框+resetFields无法回显
  • 【物联网原理与运用】知识点总结(上)
  • node-sass@4.14.1报错的最终解决方案分享
  • Markdown中状态图的用法
  • Spring Boot教程之五十二:CrudRepository 和 JpaRepository 之间的区别
  • 一个个顺序挨着来 - 责任链模式(Chain of Responsibility Pattern)
  • LabVIEW之树形控件