List.of()的坑——不能够序列化
场景:在dubbo接口中返回了空集合是使用了List.of() 方法创建了个空的集合,放入到响应数据中
报错信息如下:
Exception in thread "main" com.alibaba.com.caucho.hessian.io.HessianFieldException: com.demo.SerializeTest$ResponseDto.data: java.util.CollSer:java.lang.reflect.InvocationTargetException
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.logDeserializeError(JavaDeserializer.java:168)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:415)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:277)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:204)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2848)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2175)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2104)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2148)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2104)
at org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput.readObject(Hessian2ObjectInput.java:101)
at com.demo.SerializeTest.main(SerializeTest.java:32)
Caused by: com.alibaba.com.caucho.hessian.io.IOExceptionWrapper: java.util.CollSer:java.lang.reflect.InvocationTargetException
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:291)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:204)
at com.alibaba.com.caucho.hessian.io.SerializerFactory.readObject(SerializerFactory.java:548)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2850)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2773)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2308)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2747)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2308)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2110)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2104)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:411)
... 9 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.resolve(JavaDeserializer.java:300)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:282)
... 19 more
Caused by: java.io.InvalidObjectException: null array
at java.base/java.util.CollSer.readResolve(ImmutableCollections.java:1091)
... 25 more
Process finished with exit code 1
从报错信息中发现使用了Hessian2Input.readObject()方法时报错,模拟下报错的场景,复现下问题
模拟代码:
import com.tianrui.base.response.ResponseDTO;
import lombok.Data;
import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput;
import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class SerializeTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// m1();
List<Student> data = List.of();
// data = new ArrayList<>();
ResponseDto<List<Student>> responseDto = new ResponseDto<>(data);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Hessian2ObjectOutput hessian2ObjectOutput = new Hessian2ObjectOutput(byteArrayOutputStream);
hessian2ObjectOutput.writeObject(responseDto);
hessian2ObjectOutput.flushBuffer();
var s = new Hessian2ObjectInput(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())).readObject(responseDto.getClass());
System.out.println(s);
}
@Data
public static class ResponseDto<T> implements Serializable {
private static final long serialVersionUID = -2354066777812251826L;
private T data;
public ResponseDto(T data) {
this.data = data;
}
}
@Data
public static class Student implements Serializable{
private static final long serialVersionUID = 6322616407817236979L;
private String name;
public Student(String name) {
this.name = name;
}
}
}
当List data 使用 List.of() 赋值一个空集合时,报错信息复现,使用 new ArrayList<>() 的方式赋值一个空集合时,报错消失。问题解决了,比较下 List.of() 和 new ArrayList<>() 有什么区别?
List.of() 源码
static <E> List<E> of() {
return ImmutableCollections.emptyList();
}
ImmutableCollections.emptyList()的源码:
@SuppressWarnings("unchecked")
static <E> List<E> emptyList() {
return (List<E>) ListN.EMPTY_LIST;
}
(List) ListN.EMPTY_LIST; 源码:
static final class ListN<E> extends AbstractImmutableList<E>
implements Serializable {
static final List<?> EMPTY_LIST = new ListN<>();
@Stable
private final E[] elements;
static final List<?> EMPTY_LIST = new ListN<>(); 源码;
这个 ListN 的类虽然实现了 Serializable 序列化接口,但是并没有 声明 serialVersionUID,因此无法进行序列化
在看下ArrrayList的源码