2

そのため、最近、特定のアプリケーションを構成するためのツールに取り組んでいました。SQL スクリプトを生成し、いくつかの XML ファイルを作成する基本的なツールで十分です。この間、AbstractTableModel の独自の実装で一連の JTable オブジェクトを作成しました。すべてを構築し、AbstractTableModel (ObjectStreamWriter を使用してディスクに書き込まれたばかり) を使用して保存と読み込みをテストしている時点で、シリアル化に失敗しました。何が起こっているのかを理解するのにほぼ一日かかりました。それらをシリアライズしようとすると、java.lang.reflect.Constructor で NotSerializableException が発生します。テーブル モデルにはシリアル化可能なエンティティしか含まれておらず、アタッチしたすべてのリスナーもシリアル化可能であったため、これが何なのかわかりませんでした。親クラスもシリアライズ可能です。多くの掘り下げと、ここからのいくつかの役立つ投稿の後、TableModelListener を AbstractTableModel 実装に追加すると、追加したものに加えて、タイプ javax.swing.event.TableModelListener の別のリスナーが追加されることがわかりました。 t シリアライズ可能 (参照インターフェイスについてはhttp://docs.oracle.com/javase/7/docs/api/javax/swing/event/TableModelListener.html、実装はわかりません)。編集モデルはこのシリアル化不可能なリスナーを追加しませんが、JTable は追加します。私の質問は本質的に、なぜこのオブジェクトが独自の非シリアル化可能オブジェクトを内部的に追加し、実際にシリアル化可能を実装しているという事実を否定するのでしょうか? これはバグとして報告する必要がありますか?

参考までに、私が行った回避策は、すべてのリスナーを単純に削除し、シリアル化してから、リスナーを再度追加することでした。逆シリアル化するときは、作成したものを追加するだけで済み、モデルは別のものを独自に作成しました。

編集 setValueAt() メソッドを呼び出して提供されるシリアライザ クラスを使用して、このモデルをシリアライズしてみてください。

import java.io.Serializable;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

public class BlankTableModel extends AbstractTableModel implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 6063143451207205385L;

public BlankTableModel()
{
    this.addTableModelListener(new InnerTableModelListener());
}

@Override 
public void setValueAt(Object o, int x, int y)
{
    this.fireTableChanged(new TableModelEvent(this, x, y));
}

public int getColumnCount() {
    // TODO Auto-generated method stub
    return 2;
}

public int getRowCount() {
    // TODO Auto-generated method stub
    return 2;
}

public Object getValueAt(int arg0, int arg1) {
    // TODO Auto-generated method stub
    return "Test Data";
}

private void save()
{   
    Serializer.SerializeObject(this);
}

@Override
public boolean isCellEditable(int rowindex, int colindex)
{
    return true;
}

private class InnerTableModelListener implements TableModelListener, Serializable
{

    @Override
    public void tableChanged(TableModelEvent arg0) {
        save();         
    }

}

}

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Serializer {

public static void SerializeObject(Serializable object)
{
    File out = new File("USE A VALID PATH");
    if (!out.exists())
    {
        try {
            out.createNewFile();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
    else
    {
        out.delete();
        try {
            out.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try (FileOutputStream fos = new FileOutputStream(out);
            ObjectOutputStream oos = new ObjectOutputStream(fos))
    {
        oos.writeObject(object);
    }catch (Exception e)
    {
        e.printStackTrace();
    }
}

}

次に、保存方法をこれに置き換えてみてください

private void save()
{   
    for (TableModelListener l : this.getTableModelListeners())
    {
        this.removeTableModelListener(l);
    }
    Serializer.SerializeObject(this);
    this.addTableModelListener(new InnerTableModelListener());
}

ここに簡単なGUIがあります

import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JTable;


public class MainForm extends JFrame {

public static void main(String[] args)
{
    MainForm form = new MainForm();
    form.show();
}

public MainForm()
{
    this.setBounds(100, 100, 600, 600);
    BlankTableModel model = new BlankTableModel();
    JTable table = new JTable(model);
    table.setPreferredSize(new Dimension(500,500));
    this.getContentPane().add(table);
}

}
4

1 に答える 1

3

JTable、あ、TableModelListener自前TableModelですSerializable。あなたの習慣TableModelSerializable. 以下に示すように、追加を追加TableModelListenerしてもSerializable違いはありません。いくつかの提案:

  • に含まれるデータ構造TableModelがそれ自体であることを確認しますSerializable。これがバグである限り、モデルの内部データ構造だけをシリアル化できる可能性があります。例えば、

    System.out.println(copyObject(data));
    
  • このコンテキストでシリアライゼーションを使用するという選択を批判的に検討してください。有効な Java: 第 11 章シリアライゼーションも参照してください。

補遺:インスタンス化するように例を更新し、JTableシリアル化を使用してテーブルを複製し、コピーを更新して両方を表示しました。

画面:

画像

コンソール:

新しいデータ

SSCCE:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

/* @see http://stackoverflow.com/a/19300995/230513 */
public class SerializationTest {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JTable table = new JTable(new BlankTableModel());
                JTable copy = copyObject(table);
                copy.setValueAt("New data", 0, 0);

                JFrame f = new JFrame("SerializationTest");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setLayout(new GridLayout(0, 1, 5, 5));
                f.add(table, BorderLayout.NORTH);
                f.add(copy, BorderLayout.SOUTH);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });

    }

    private static class BlankTableModel extends AbstractTableModel implements Serializable {

        private static final long serialVersionUID = 3141592653589793L;
        private String data = "Test data";

        public BlankTableModel() {
            this.addTableModelListener(new InnerTableModelListener());
        }

        @Override
        public void setValueAt(Object o, int row, int col) {
            data = o.toString();
            this.fireTableCellUpdated(row, col);
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public int getRowCount() {
            return 2;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return data;
        }

        private void save() {
            BlankTableModel model = copyObject(this);
            System.out.println(model.getValueAt(0, 0));
        }

        @Override
        public boolean isCellEditable(int row, int col) {
            return true;
        }

        private class InnerTableModelListener implements TableModelListener, Serializable {

            private static final long serialVersionUID = 2718281828459045L;

            @Override
            public void tableChanged(TableModelEvent e) {
                save();
            }
        }
    }

    private static <T extends Serializable> T copyObject(final T source) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(source);
            ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(baos.toByteArray()));
            final T copy = (T) ois.readObject();
            return copy;
        } catch (Exception e) {
            throw new AssertionError("Error copying: " + source);
        }
    }
}
于 2013-10-10T16:12:19.027 に答える