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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

发表回复

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

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