Java GUI反序列化期间Swing启动侦听器
今天,我遇到了一个非常严重的错误,它涉及到在使用标准Java序列化API进行GUI反序列化期间触发swing侦听器。要简明扼要地解释如何复制这种行为有点困难,所以我在下面发布了一个小测试用例。这个测试用例不会抛出任何异常,不会触发任何编译器警告,当然也不会有定义良好的行为。这是甲骨文软件包互操作文档中的一个bug、灰色区域,还是仅仅是某个人以前尝试过的东西 为了阐明我最初的用例,我试图在从磁盘重新加载配置组件时自动更新资产编辑器中的几个选项卡Java GUI反序列化期间Swing启动侦听器,java,swing,serialization,serializable,Java,Swing,Serialization,Serializable,今天,我遇到了一个非常严重的错误,它涉及到在使用标准Java序列化API进行GUI反序列化期间触发swing侦听器。要简明扼要地解释如何复制这种行为有点困难,所以我在下面发布了一个小测试用例。这个测试用例不会抛出任何异常,不会触发任何编译器警告,当然也不会有定义良好的行为。这是甲骨文软件包互操作文档中的一个bug、灰色区域,还是仅仅是某个人以前尝试过的东西 为了阐明我最初的用例,我试图在从磁盘重新加载配置组件时自动更新资产编辑器中的几个选项卡 package com.ihateswing.ssc
package com.ihateswing.ssce;
import java.awt.BorderLayout;
public class SSCE implements Serializable {
private class Internal extends JPanel {
private final JComboBox<String> m_cb = new JComboBox<String>();
Internal(final JComboBox<String> cb) {
cb.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
DefaultComboBoxModel<String> dcbm = new DefaultComboBoxModel<String>();
for (int i = 0; i < cb.getModel().getSize(); ++i) {
dcbm.addElement(cb.getModel().getElementAt(i));
}
m_cb.setModel(dcbm);
}
});
super.add(m_cb);
}
}
private JFrame frame;
private JComboBox<String> jce = new JComboBox<String>();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SSCE window = new SSCE();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SSCE() {
initialize();
}
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
jce.setSelectedIndex(0); // <-- Seems to have undefined behavior?
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jce.setModel(new DefaultComboBoxModel<String>());
frame.getContentPane().add(new Internal(jce), BorderLayout.NORTH);
frame.getContentPane().add(jce, BorderLayout.CENTER);
JButton btnAddRandomItem = new JButton("Break");
btnAddRandomItem.addActionListener(new AbstractAction() {
private static final long serialVersionUID = 1L;
private int i;
public void actionPerformed(ActionEvent e) {
try {
((DefaultComboBoxModel<String>) jce.getModel())
.addElement(String.valueOf(i++));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(SSCE.this);
ByteArrayInputStream in = new ByteArrayInputStream(baos
.toByteArray());
ObjectInputStream oin = new ObjectInputStream(in);
oin.readObject();
// The line below updates 'Internal' as expected, uncomment
// to see...
// however with the listener fired from the serialization
// method, it breaks?
// jce.setSelectedIndex(0);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
frame.getContentPane().add(btnAddRandomItem, BorderLayout.SOUTH);
}
}
package com.ihateswing.ssce;
导入java.awt.BorderLayout;
公共类SSCE实现可序列化{
私有类内部扩展JPanel{
私有最终jcombox m_cb=新jcombox();
内部(最终JCOMBOX cb){
cb.addActionListener(新的AbstractAction(){
@凌驾
已执行的公共无效操作(操作事件e){
DefaultComboxModel dcbm=新的DefaultComboxModel();
对于(int i=0;i jce.setSelectedIndex(0);//我不认为您正在更新您认为正在更新的内容。如果您将每个println m_cb.hashCode()附加到其中,则这是相同的输出。请注意,下面的“Set…”错误消息表示每次都在不同的m_cb实例上设置模型
Set Internal.m_cb's model with 1 elements: 44160343
Set Internal.m_cb's model with 1 elements: 1436306574
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 2 elements: 2094948113
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 3 elements: 915510800
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 4 elements: 853795873
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 5 elements: 616759228
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 6 elements: 1385385632
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 7 elements: 1283006722
After returning, Internal.m_cb's model size is 1 elements: 44160343
在每次序列化中都会创建一个新的m_cb实例,您正在设置它的模型,但是这些新的组合框不会显示在您的框架中。它是如何“断开”的“internal”中的组合框不会随“SSCE”中的模型更新……但是,如果打印出正在设置的模型,则模型的每个元素都会在action listener中进行设置。应用程序是可编译和可运行的。请测试并查看。我将添加示例输出。Post已更新。我只能推测Java的序列化过程将覆盖对列表模型所做的更改…但这些更改在调用“defaultReadObject”之后发生,这对我来说似乎不太直观。似乎我必须重新阅读序列化规范。谢谢。
Set Internal.m_cb's model with 1 elements: 44160343
Set Internal.m_cb's model with 1 elements: 1436306574
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 2 elements: 2094948113
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 3 elements: 915510800
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 4 elements: 853795873
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 5 elements: 616759228
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 6 elements: 1385385632
After returning, Internal.m_cb's model size is 1 elements: 44160343
Set Internal.m_cb's model with 7 elements: 1283006722
After returning, Internal.m_cb's model size is 1 elements: 44160343