zoukankan      html  css  js  c++  java
  • 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。至此问题解决。

  • 相关阅读:
    Leap Ftp 3.0注册码
    Access数据库导入到MSSQLServer数据库中的三种办法。
    flash上传插件uploadify详解_图片批量上传_更新数据库
    Winform(c#)手机号码归属地查询的实现
    百度再度出现故障,目前很多地区无法正常访问!
    windows 2000/2003 自动重启/定时重启
    js初步学习
    考研之三战讨论
    C++中的map学习
    BUPT 63T 高才生 找最佳基站
  • 原文地址:https://www.cnblogs.com/succour/p/10245788.html
Copyright © 2011-2022 走看看