经过

今天在测试 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 搞蒙了, 找了个没实现序列化的类来背锅.