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)

从异常堆栈可以很快定位到是CustomConditionoperators没有序列化导致的

报错类的截图

图 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) {
 // (BooleanOperator<String> & Serializable) 是Java8的新语法
 return (BooleanOperator<String> & Serializable)  o -> true;
}

或者这样实现一个业务上的默认返回,单例实现

参考文献