发现问题

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

因此我写了一个通用接口。接口中有传递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。至此问题解决。

jackson对Exception类型对象的序列化与反序列化的更多相关文章

  1. (记录)Jedis存放对象和读取对象--Java序列化与反序列化

    一.理论分析 在学习Redis中的Jedis这一部分的时候,要使用到Protostuff(Protobuf的Java客户端)这一序列化工具.一开始看到序列化这些字眼的时候,感觉到一头雾水.于是,参考了 ...

  2. Java对象的序列化和反序列化[转]

    Java基础学习总结--Java对象的序列化和反序列化 一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化.把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用 ...

  3. Java对象的序列化与反序列化-Json篇

    说到Java对象的序列化与反序列化,我们首先想到的应该是Java的Serializable接口,这玩意在两个系统之间的DTO对象里面可能会用到,用于系统之间的数据传输.或者在RPC(远程方法调用)时可 ...

  4. ObjectOutputStream和ObjectInputStream对对象进行序列化和反序列化

    1 Java序列化和反序列化简介 Java序列化是指把对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为java对象的过程. 我们把对象序列化成有序字节流,保存到本地磁盘或者Redis等 ...

  5. java中对象的序列化和反序列化

    [对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...

  6. Java对象的序列化与反序列化

    序列化与反序列化 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等.在网络传输过程中,可以是字节或是 ...

  7. 【Java IO流】对象的序列化和反序列化

    对象的序列化和反序列化 1)对象序列化,就是将Object对象转换成byte序列,反之叫对象的反序列化. 2)序列化流(ObjectOutputStream),是字节的过滤流—— writeObjec ...

  8. 利用JavaScriptSerializer类 进行Json对象的序列化和反序列化和过滤

    项目下载:JavaScriptSerializer_对JSON对象序列化与反序列化及过滤器 利用<JavascriptSerializer类> 进行Json对象的序列化和反序列化 1. 首 ...

  9. 对象的序列化与反序列化---IO学习笔记(四)

    对象的序列化,反序列化 对象的序列化: 就是将Object转换成byte序列 对象的反序列化: 将byte序列转换成Object 序列化流.反序列化流 序列化流(ObjectOutputStream) ...

随机推荐

  1. Redis数据类型操作说明

    List数据操作 lpush 语法:lpush key value [value…] 作用:将一个或多个值 value 插入到列表 key 的表头(最左边),从左边开始加入值,从左到右的顺序依次插入到 ...

  2. PHP配置文件(php.ini)详解

    [PHP] ; PHP还是一个不断发展的工具,其功能还在不断地删减 ; 而php.ini的设置更改可以反映出相当的变化, ; 在使用新的PHP版本前,研究一下php.ini会有好处的 ;;;;;;;; ...

  3. 在js中获取 input checkbox里选中的多个值

    思路:利用name属性值获取checkbox对象,然后循环判断checked属性(true表示被选中,false表示未选中).下面进行实例演示: 1.html中展示: <input type=& ...

  4. flutter 跳转至根路由

    上代码 //flutter 登录后跳转到根路由 Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute(builder: (co ...

  5. bzoj1497: [NOI2006]最大获利(最小割)

    传送门 第一眼看去:好难 第二眼:不就是个裸的最大权闭合子图么…… 我们从源点向所有用户连边,容量为收益,用户向自己的中转站连边,容量为INF,中转站向汇点连边,容量为费用 那么总收益-最小割就是答案 ...

  6. Codeforces Round #590 (Div. 3) E. Special Permutations

    链接: https://codeforces.com/contest/1234/problem/E 题意: Let's define pi(n) as the following permutatio ...

  7. Tomcat配置多站点

    tomcat配置多个站点.可以这样. 在conf文件夹下创建文件:..conf\Catalina\localhost\aa.xml aa.xml的内容.如: <?xml version=&quo ...

  8. springboot的application.yml配置详解

    https://www.cnblogs.com/lqtbk/p/9843401.html https://blog.csdn.net/yelllowcong/article/details/79216 ...

  9. Java进阶知识14 Struts2中的S标签

    1.A 开头 <s:a href=""></s:a> //超链接,类似于html里的<a></a> <s:action nam ...

  10. deepin Linux 日常命令、插件、方法等汇总【更新中】

    查看系统编码: dawn@dawn-PC:~$ locale LANG=zh_CN.UTF- LANGUAGE=zh_CN LC_CTYPE="zh_CN.UTF-8" LC_NU ...