如何以最简洁方式区分序列化后的相同对象?异常类场景问询
解决序列化后父子类异常无法区分的简洁方案
这个问题我之前在做分布式服务重试的时候实打实踩过坑——核心就是序列化过程中丢失了类型标识,导致子类因为没有新增字段,被序列化框架当成父类处理,反序列化后自然还原不成原来的子类,重试框架也就没法判断了。下面给你几个最简洁的解决思路,按推荐程度排序:
1. 给父类添加序列化类型注解(JSON序列化场景首选)
如果你们用的是Jackson这类JSON序列化框架,直接在父类ServiceException上加上类型标识注解,让序列化时自动带上类的全限定名:
import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") class ServiceException extends RuntimeException { private Status status; private String someString; // 省略样板代码 }
这样序列化后的JSON里会多一个"@class": "com.yourpackage.RetryableServiceException"的字段,反序列化时框架能精准还原成对应的子类,完全不用修改子类代码,干净又省心。
2. 给子类加一个无业务逻辑的标记字段(通用场景)
不管是Java原生序列化还是JSON序列化,给RetryableServiceException加一个纯标记用的字段就行,不需要任何业务逻辑:
class RetryableServiceException extends ServiceException { // 标记字段,固定值即可,序列化后就能和父类区分开 private boolean retryable = true; // 或者用serialVersionUID,Java序列化时靠这个区分类 // private static final long serialVersionUID = 123456L; }
这个方案的好处是零侵入父类代码,子类只加一行代码就能解决问题,对现有业务逻辑完全没有影响。
3. 利用现有字段携带重试标记(备选方案)
如果不想加新字段,也可以在子类的构造方法里给现有字段加标记,比如给someString加前缀,或者给status设置特定枚举值:
class RetryableServiceException extends ServiceException { public RetryableServiceException(Status status, String someString) { // 给status设置重试专属枚举值,或者给someString加前缀 super(Status.RETRYABLE, "[RETRYABLE]" + someString); } }
不过这个方案会污染业务字段,后续如果要修改标记逻辑还得改业务代码,所以只推荐在前两种方案没法用的时候再考虑。
内容的提问来源于stack exchange,提问作者StolenKitten
相关产品推荐
相关产品推荐

