1 2 3 4 5 6 7 8 9 10 11 12
| cover: "" category: "" tags: - blog status: 已发布 date: "2021-06-28 16:49:00" catalog: - blog urlname: lambda-serializable title: java8 lamdba 序列化异常 summary: "" sort: ""
|
Lambda 的序列化问题
背景
最近遇到一个序列化的问题,是在跑测试用例的时候,遇到 RPC 调用后返回的数据无法解析。我们用的motan
的 rpc,内部序列化用的Heassin2
1 2 3
| com.xxx.api.motan.exception.MotanFrameworkException: error_message: encode error!type:response, com.xxx.api.motan.rpc.DefaultResponse@3368de44, origin errmsg:Serialized class com.xxx.abtest.traffic.rpc.condition.CustomCondition$$Lambda$462/331671338 must implement java.io.Serializable field: com.xxx.abtest.traffic.rpc.condition.CustomCondition.operators class: com.xxx.abtest.traffic.rpc.condition.CustomCondition (object=com.xxx.abtest.traffic.rpc.condition.CustomCondition@58a58a69)
|
从异常堆栈可以很快定位到是CustomCondition
的operators
没有序列化导致的
报错类的截图
图 1-1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private static BooleanOperator<String> getCustomConditionOperator(ConditionItem item) { String type = item.getType(); String source = item.getSource(); CustomConditionTypeEnum conditionTypeEnum = CustomConditionTypeEnum.getByType(type); if (conditionTypeEnum == null) { return o -> true;7 } switch (conditionTypeEnum) { case SET_CONTAINS: Set<String> set = new HashSet<>(); try { set = JsonUtils.jsonStr2Set(source, String.class); } catch (Exception ignore) {} return new ContainsOperator<String>(set);
|
一开始是思路没有顺着构造函数去想,就想着Map
如何序列化
后面顺着大佬的思路看了,是lambda
使用姿势的问题。从图 1-2 可以看出需要返回一个BooleanOperator<String>
类型,
1 2 3 4 5 6
| public interface BooleanOperator<T> {
boolean isTrue(T other);
}
|
一个 Lambda 能否序列化, 要以它捕获的参数以及 target type 能否序列化为准。
可以看出我们我们捕获到的参数是BooleanOperator<String>
,在用于序列化的 writeReplace() 方法中,SerializedLambda 对象不但包含了符号信息,还把这个 method reference 所捕获的引用也写进去了。由于BooleanOperator
并没有序列化,所以会抛出NotSerializableException
解决办法
1 2 3 4 5
| if (conditionTypeEnum == null) { return (BooleanOperator<String> & Serializable) o -> true; }
|
或者这样实现一个业务上的默认返回,单例实现
参考文献