Spring中的Spring / JUnit序列化在Java中初始化了ArrayList

时间:2011-03-07 13:44:23

标签: java serialization

在编写简单的远程测试时,我遇到了一个涉及DBI(双括号初始化)的令人惊讶的情况,我一直无法完全理解,所以我会请求一些帮助。

请考虑以下代码:

public class RemotingTest {

@Autowired
private RemotingTestController remotingTestController;

//DBI
List<SomeBean> mockList = new ArrayList<SomeBean>(){{
        add(MockFactoryBean.getMockBean());
}};

@Test
public void testRemoting() {
    try {
        // controller code is not relevant - it simply passes this list 
        // via Spring's HttpInvokerProxyFactoryBean to a session facade which then 
        // passes the list further down the SOA stack...
        String result = remotingTestController.createBeanRemotely(mockList); 
        log.debug(result);
    } catch (Exception e) {
        fail();
        e.printStackTrace();
    }
}

}

此代码在运行时发生爆炸,出现以下错误,对我来说没有任何意义:

java.io.NotSerializableException: org.stackoverflow.RemotingIntegrationTest
  at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
  at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
  <<stacktrace snipped>>
  at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:174)
  at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:142)
... 33 more

但是,如果我只是省略DBI并使用vanilla样式模式将元素添加到列表中,如:

    public class RemotingTest {

@Autowired
private RemotingTestController remotingTestController;

List<SomeBean> mockList = new ArrayList<SomeBean>();

@Test
public void testRemoting() {
    mockList.add(MockFactoryBean.getEcopStatusMock());

    try {
    //this block stays the same
        } catch (Exception e) {
        //.....
    }
}

}

一切正常,序列化顺畅。我甚至试图让测试序列化(颤抖),但是由于测试以更有趣的错误消失了,所以没有产生任何结果 - {{1}应该实现Serializable:)

问题是 - 为什么会这样?研究DBI有点让我相信通过向列表中添加一个元素,这种方式实际上使两个对象 - 预期的HttpInvokerServiceExporter和一个新的子类 {{ 1}}包含添加元素的对象;这会以某种方式混淆Spring的Remoting并因NotSerializableException而死于可怕的死亡。

但是,我不确定,如果这就是幕后发生的事情,那么任何帮助解释这一点都会受到赞赏。

环境使用以下内容:

  • Spring 3.0.4
  • JDK 1.6.0 Update 23
  • IceFaces 1.8.2

1 个答案:

答案 0 :(得分:5)

这种情况正在发生,因为双括号初始化语法创建了ArrayList的匿名子类,并且像所有匿名类一样,它包含对其父对象的隐式引用(在本例中为您的测试)。

为了可序列化,父对象(即您的测试)也必须是可序列化的。这显然不是你想要的。你只需要避免使用这种语法,这很方便。

列表同样方便的替代方案是:

List<SomeBean> mockList = Arrays.asList(
    bean1, bean2, bean3
);

构建地图时,DBI语法才真正引人注目。