Java 序列化类时报 Caused by java.io.NotSerializableException
经过
今天在测试 ActiveMQ 时调用 jsmTemplate. convertAndSend(String destinationName, Object message) 方法时, 报java.io.NotSerializableException 异常.
TestMessage 类
public class TestMessage implements Serializable {
private static final long serialVersionUID = -2132582539599141027L;
private Integer id;
private String msg;
private List<TestMessage> list;
// 省略 get and set
}
调用发送 MQ 的方法
@Test
public void test() {
TestMessage testMessage = new TestMessage();
testMessage.setId(1);
testMessage.setMsg("对象消息。。。");
TestMessage testMessage2 = new TestMessage();
testMessage2.setId(12);
testMessage2.setMsg("对象消息2。。。");
// 将 testMessage2 对象添加到 testMessage 对象的 list 里面
testMessage.setList(new ArrayList() );
jsmTemplate.convertAndSend("study.queue.object", testMessage);
}
报错信息 :
Caused by: java.io.NotSerializableException: com.xxx.demo.DemoApplicationTests
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.activemq.command.ActiveMQObjectMessage.storeContent(ActiveMQObjectMessage.java:120)
... 42 more
分析原因:
首先要序列化 TestMessage , 要保证 TestMessage 本身和 非 null 的成员属性 都要实现 Serializable 接口. Integer String 和 ArrayList 类都已经实现了这个接口.
这里很奇怪的是报的测试类的对象没有序列化, 难道调用方法的类也要实现序列化?
于是我给测试类也实现了 Serializable 接口, 这时又报了如下错误
Caused by: java.io.NotSerializableException: org.springframework.jms.core.JmsTemplate
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.activemq.command.ActiveMQObjectMessage.storeContent(ActiveMQObjectMessage.java:120)
... 42 more
这已经没有办法了, 我不能去让 Spring jms 的 JmsTemplate 也实现序列化吧, 我相信 Sping 是不会让我的 Pull request 的.
这时, 我猛然想起来会不会是因为 testMessage.setList(new ArrayList() );
这段代码. 这里使用了一个匿名内部类的写法. 而这个匿名内部类只是继承了 ArrayList 并没有实现 Serializable 接口, 所以无法序列化.
解决:
于是我将代码改成如下形式, 用常规的 new 一个 ArrayList 丢到 testMessage 里
TestMessage testMessage = new TestMessage();
testMessage.setId(1);
testMessage.setMsg("对象消息。。。");
TestMessage testMessage2 = new TestMessage();
testMessage2.setId(12);
testMessage2.setMsg("对象消息2。。。");
// testMessage.setList(new ArrayList() );
// 不使用匿名内部类
List<TestMessage> testMessages = new ArrayList();
testMessages.add(testMessage2);
testMessage.setList(testMessages);
producerService.sendMessage("study.queue.object", testMessage);
最终真的成功, 没有报错.
最后:
最后再回过头来想想为什么
Caused by: java.io.NotSerializableException: com.xxx.demo.DemoApplicationTests
Caused by: java.io.NotSerializableException: org.springframework.jms.core.JmsTemplate
这两个报错信息这么怪, 可能是因为匿名内部类不存在 对应的 class 对象, 把 JVM 搞蒙了, 找了个没实现序列化的类来背锅.