2008/08/08

ListとObjectOutputStream

なんか苛まれている挙動。ListをもっているオブジェクトをObjectOutputStreamで送ろうとしてもデータが足りない。

import java.io.*; import java.net.*; import java.util.*; public class Server { public static void main(String[] args) { ObjectInputStream in = null; ObjectOutputStream out = null; ServerSocket ss = null; try { ss = new ServerSocket(1234); while (true) { Socket s = null; try { s = ss.accept(); in = new ObjectInputStream(s.getInputStream()); Test t = null; try { while ( (t = (Test)in.readObject()) != null) { System.out.println(t.toString()); } } catch(EOFException e) { System.out.println("Disconnected"); } } finally { if (out != null) { try { out.close(); } catch(Exception e) {} } if (in != null) { try { in.close(); } catch(Exception e) {} } if (s != null) { try { s.close(); } catch(Exception e){} } } } } catch (Exception e) { e.printStackTrace(); } finally { if (ss != null) { try { ss.close(); } catch(Exception e) {} } } } }

import java.io.*; import java.net.*; import java.util.*; public class Client { public static void main(String[] args) { ObjectInputStream in = null; ObjectOutputStream out = null; Socket s = null; try { s = new Socket("localhost", 1234); out = new ObjectOutputStream(s.getOutputStream()); Test t = new Test("test1"); t.addTest2("test2-1"); System.out.println("Building Test1 :" + t.toString()); out.writeObject(t); out.flush(); List<Test2> l = t.getTest2s(); l.add(new Test2("test2-2")); System.out.println("Building Test2 :" + t.toString()); out.writeObject(t); out.flush(); t.addTest2("test2-3"); System.out.println("Building Test3 :" + t.toString()); out.writeObject(t); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (Exception e) {} } if (s != null) { try { s.close(); } catch (Exception e) {} } } } }

というクラサバがある。で、送りたいデータは

import java.util.*; import java.io.*; class Test implements Serializable { List<Test2> test2s; private String name; public Test(String name) { this.name = name; test2s = new ArrayList<Test2>(); } public void addTest2(String s) { test2s.add(new Test2(s)); } public List<Test2> getTest2s() { return test2s; } public String getName() { return name; } public String toString() { StringBuffer buf = new StringBuffer(); buf.append("Test : name => " + name + ", "); buf.append(" test2s => ["); for (Test2 t : test2s) { buf.append("{" +t.toString() + "}, "); } buf.append("]"); return buf.toString(); } } class Test2 implements Serializable { private String name; public Test2(String name) { this.name = name; } public String getName() { return name; } public String toString() { return "Test2 : " + name; } }

というListをもった内容。

で実行結果が

クライアント側

Building Test1 :Test : name => test1, test2s => [{Test2 : test2-1}, ] Building Test2 :Test : name => test1, test2s => [{Test2 : test2-1}, {Test2 : test2-2}, ] Building Test3 :Test : name => test1, test2s => [{Test2 : test2-1}, {Test2 : test2-2}, {Test2 : test2-3}, ]

サーバ側

Test : name => test1, test2s => [{Test2 : test2-1}, ] Test : name => test1, test2s => [{Test2 : test2-1}, ] Test : name => test1, test2s => [{Test2 : test2-1}, ] Disconnected

サーバ側にtest2-2, 2-3が届かない。うーむ。。。

どうやら、ObjectOutputStreamが一度シリアライズしたものをキャッシュとして持つようだ。

out.flush()で書き込んだあと、out.reset()でストリームを初期化してやると、正常に送信できた。

APIだけだと分かりにくい。Java オブジェクト直列化仕様

2.1 ObjectOutputStream クラス
クラス ObjectOutputStream は、オブジェクト直列化を実装するためのものです。このクラスは、すでに直列化されたオブジェクトセットなどのストリームの状態を維持します。そのメソッドは、直列化するオブジェクトのトラバーサルを制御して、指定されたオブジェクトと参照するオブジェクトを保管します。

reset メソッドは、ストリーム状態を再設定して、構成時の状態に戻します。 ・・・中略・・・これは、オブジェクトの内容やオブジェクトを再送信しなければならない場合に有用です。
ってちょこっと書いてあったからなんとなくやってみたら当たった。

解決に徹夜したのでメモ。

0 件のコメント: