发现问题

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

因此我写了一个通用接口。接口中有传递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. 详解mpstat等性能监测命令的使用

    mpstat是Multiprocessor Statistics的缩写,是实时监控工具,报告与cpu的一些统计信息这些信息都存在/proc/stat文件中,在多CPU系统里,其不但能查看所有的CPU的 ...

  2. libusb_bulk_transfer 异步同步

    同步方式 libusb_bulk_transfer(devh, ep_bulk, buf, CAM_BUF_SZ, &len, timeout); 进入libusb研究,发现libusb是采用 ...

  3. MySQL--------SQL优化审核工具实战

    1. 背景 SQLAdvisor是由美团点评公司技术工程部DBA团队(北京)开发维护的一个分析SQL给出索引优化建议的工具.它基于MySQL原生态词法解析,结合分析SQL中的where条件.聚合条件. ...

  4. Codeforces Round #591 (Div. 2, based on Technocup 2020 Elimination Round 1) D. Sequence Sorting

    链接: https://codeforces.com/contest/1241/problem/D 题意: You are given a sequence a1,a2,-,an, consistin ...

  5. Java SE练习 - 对dom4j解析、反射的综合练习

    原 Java SE练习 - 对dom4j解析.反射的综合练习 2017年12月13日 14:41:07 都说名字长不会被发现 阅读数 138 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa ...

  6. Comet OJ - Contest #11 A 水题

    Code: #include <bits/stdc++.h> #define N 3000000 using namespace std; char str[N]; int main() ...

  7. c/c++读取一行可以包含空格的字符串(getline,fgets用法)

    1.char[]型 char buf[1000005]; cin.getline(buf,sizeof(buf)); 多行文件输入的情况: while(cin.getline(buf,sizeof(b ...

  8. UVALive 7178 Irrational Roots 多项式的根

    题意:给你一个首项为1的n阶方程(n<=8),求出方程的无理数的根: #include <cstdio> #include <iostream> #include < ...

  9. Codevs 2188 最长上升子序列(变式)

    2188 最长上升子序列 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description LIS问题是最经典的动态规划基础问题之一.如果要求一个 ...

  10. noi 2011

    描述 已知长度最大为200位的正整数n,请求出2011^n的后四位. 输入 第一行为一个正整数k,代表有k组数据,k<=200接下来的k行, 每行都有一个正整数n,n的位数<=200 输出 ...