尝试扩展Hessian早期版本反序列化,使其支持jdk8可序列化lambda表达式
引出
dubbo版本2.5.3
内置默认序列化hessian.io 在调用传参有函数接口时,客户端序列化失败。
// 无法序列化的字段
private Predict<T> bar = any -> true;
原因是Predict并未实现Serializable,自定义实现后,
@FunctionalInterface
public interface SerializablePredict<T> extends Predict<T>, Serializable {
}
客户端不报错,服务端反序列化失败。
原因是序列化时,上述对象会被序列化成SerializedLambda
的一个实例,显然服务端hessian没有处理该对象的反序列化实现,而使用默认反序列化器JavaDeserializer
,最后报错。
解决
1. 实现反序列化逻辑
gayhub搜最新的hessian源码,本期望有实现直接拷过来即可,结果源码里搜关键字Lambda没看到半行代码(也可能有用到jdk默认实现,隐藏到默认逻辑中了),那自己弄个吧。
本质上函数在内存中的存在是SerializedLambda
,我们需要反序列化成这个类的对象,可以复用hessian已有的JavaDeserializer
。
@Component
public class LambdaDeserializer extends AbstractDeserializer {
private static JavaDeserializer serializableLambdaDeserializer =
new JavaDeserializer(HessianAdaptSerializedLambda.class);
@Override
public Object readObject(AbstractHessianInput in) throws IOException {
return serializableLambdaDeserializer.readObject(in);
}
@Override
public Object readMap(AbstractHessianInput in) throws IOException {
return serializableLambdaDeserializer.readMap(in);
}
@Override
public Object readObject(AbstractHessianInput in, String[] fieldNames) throws IOException {
return serializableLambdaDeserializer.readObject(in, fieldNames);
}
}
hessian反序列化pojo的逻辑是,先new一个,构造器需要入参则传默认值进去,再给属性赋值。
这导致SerailizedLambda
这个类在反序列化时会遇到两个问题:
- 构造方法要求
capturedArgs
非空,但是hessian new的时候会传默认值,即null进去引起空指针 - 所有属性没有赋值方法
这玩意儿是final class,所以要自己拷改一个
import lombok.Data;
import lombok.AllArgsConstructor;
import java.io.Serializable;
import java.lang.invoke