jackson对Exception类型对象的序列化与反序列化「建议收藏」

jackson对Exception类型对象的序列化与反序列化「建议收藏」jackson对Exception类型对象的序列化与反序列化

大家好,又见面了,我是你们的朋友全栈君。

发现问题

今天在调试系统错误通知的时候遇到了一个问题。我们在系统异常时候要通过队列系统发送各种通知到团队内部成员。

因此我写了一个通用接口。接口中有传递Exception对象到队列中,再由队列消费者解析后生成消息发送出去。

这个Exception对象是先通过jackson序列化后再在队列消费端反序列化完成传递的。

但是在测试过程中发现,经过队列传递后的Exception对象丢失了很多信息,甚至连基本的class类型都不能还原。

比如一个IllegalArgumentException经过jackson的序列化与反序列化之后得到的是一个几乎空的Exception对象。从message到cause到stackTrace数据全部丢失。

例如:

IllegalStateException e = new IllegalStateException("abc");
String str = JSONSnakeUtils.writeValue(e);
Exception ex = JSONSnakeUtils.readValue(str, Exception.class);

注:以上代码中JSONSnakeUtils是我们自己封装的jackson方法,基本原样调用了jackson的objectMapper方法。

上面方法中ex对象已经和原来的e对象天差地别了。

尝试解决

然后我想到了使用java自带的序列化工具来实现。
经过以下测试:

IllegalStateException e = new IllegalStateException("abc");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(byteArrayOutputStream);
oo.writeObject(e);
oo.close();
byte[] bytes = byteArrayOutputStream.toByteArray();

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
Exception ex = (Exception) ois.readObject();

得到的ex对象原样还原了原始的e对象,说明这个思路是可行的。

最终方案

结合jackson自定义序列化与反序列化的方式,有了最终的解决方案:

首先定义自定义的序列化与反序列化方法,将经过ObjectOutputStream序列化后的byte数组转化为字符串通过json传递。再在消费端经过byte数组转换回Exception对象。代码如下:

定义序列化类
public class ExceptionJsonSerializer extends JsonSerializer<Exception> {

    @Override
    public void serialize(Exception exception, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(byteArrayOutputStream);
        oo.writeObject(exception);
        oo.flush();
        oo.close();
        byte[] bytes = byteArrayOutputStream.toByteArray();
        gen.writeRawValue("\"" + ByteArrayUtil.toHexString(bytes) + "\"");
    }

}
定义反序列化类
public class ExceptionJsonDeserializer extends JsonDeserializer<Exception> {

    @Override
    public Exception deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        String valueAsString = jsonParser.getValueAsString();
        byte[] bytes = ByteArrayUtil.hexStringToByteArray(valueAsString);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
        try {
            Exception ex = (Exception) ois.readObject();
            return ex;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        } finally {
            ois.close();
        }
    }
}
最后在对象字段上添加注解
public static class AAA {
    String xxx;
    String yyy;
    @JsonSerialize(using = ExceptionJsonSerializer.class)
    @JsonDeserialize(using = ExceptionJsonDeserializer.class)
    Exception exception;
}

OK。至此问题解决。

转载于:https://www.cnblogs.com/succour/p/10245788.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107077.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月21日 上午11:00
下一篇 2022年4月21日 上午11:20


相关推荐

  • python监控网页变化教程_Python实时监控网站浏览记录实现过程详解

    python监控网页变化教程_Python实时监控网站浏览记录实现过程详解需求:(1)获取你对象chrome前一天的浏览记录中的所有网址(url)和访问时间,并存在一个txt文件中(2)将这个txt文件发送给指定的邮箱地址(你的邮箱)(3)建立例行任务,每天定时自动完成这些操作,你就可以通过邮件查看你对象每天看啥了准备macOSSierraPython3.6Chrome发送邮件的qq邮箱地址qq邮箱授权码SMTP服务器地址:smtp.qq.com接受邮件的邮箱地…

    2022年7月16日
    20
  • navicat premium15激活码【2021.10最新】

    (navicat premium15激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html08G05E7DZH-eyJsa…

    2022年3月28日
    57
  • py3使用py3Fdfs

    py3使用py3Fdfs通过 pip 下载的 fdfs client py 只适用于 python2 版本 所以要想适用于 python3 版本 需要用 pip3installp 但是下载包之后 运行上传文件 会报错 TypeError typeobjectar notstr 要求 Fdfs client 必须传入一个 tracker 字典此

    2026年3月26日
    1
  • HTML点击按钮button跳转页面的几种实现方法

    HTML点击按钮button跳转页面的几种实现方法其实我比较喜欢第一种方法<buttononclick=”window.location.href=’../routeEdit/index.html'”type=”button”id=”add”>新增</button>方法一:在button标签中加上onclick属性,赋值为Javascript<inputtype=”button”name=”regi…

    2025年8月13日
    6
  • C语言fscanf和fprintf函数的用法详解

    C语言fscanf和fprintf函数的用法详解fscanf()和fprintf()函数与前面使用的scanf()和printf()功能相似,都是格式化读写函数,两者的区别在于fscanf()和fprintf()的读写对象不是键盘和显示器,而是磁盘文件。这两个函数的原型为:intfscanf(FILE*fp,char*format,…);intfprintf(FILE*fp,char…

    2022年10月19日
    4
  • [Windows安全设置]教你如何关闭135端口和445端口[通俗易懂]

    [Windows安全设置]教你如何关闭135端口和445端口[通俗易懂]1.关闭135端口使用Windows2000或者XP的用户今天都被那个利用RPC服务漏洞的蠕虫病毒折腾的够戗吧,该病毒主要攻击手段就是扫描计算机的135端口来进行攻击,现在教大家一种手动关闭135端口的方法,虽然不能完全解决问题,但也是能解一时的燃眉之急。更新微软的补丁还是必要的。  用一款16为编辑软件(推荐UltraEdit)打开你系统x:winntsystem32或者x:windows

    2022年10月16日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号