2006-10-20 [長年日記]
■ObjectInputStreamでカスタムクラスローダを使う
なんとかObjectInputStream#readObject()のときに、カスタムクラスローダを使えないか調べていたところ、ObjectInputStreamをサブクラス化して、
Class> ObjectInputStream#resolveClass(ObjectStreamClass)
をオーバーライドしてやれば良いらしい。
Onion開発日記(2006-10-19)
そんな手があったんだ。
ObjectInputStream#readObject()はデフォルトでは、system classloaderを使ってクラスをロードしているようなのだが、
Onion開発日記(2006-10-19)
とあるけど、「system classloaderを使」うんじゃなくて、実行スタックを遡っていって*1一番近い「null でない ClassLoader」を使うというのが正しい(ハズ)。
↓しかしこの説明分かりにくすぎ。
ここで loader は、実行スタックまでの最初の null でないクラス、または null でないクラスローダがスタック側 (resolveClass メソッドが使用する同じクラスローダの選択) にない場合は null です。
ObjectInputStream (Java 2 プラットフォーム SE v1.4.0)
私はというと、カスタムクラスローダでロードする class ではない方に
public class Foo { public static interface ObjectLoader { public Object readObject(ObjectInputStream in) throws IOException, ClassNotFoundException; } public static Object loadObject(ObjectLoader o, ObjectInputStream in) throws IOException, ClassNotFoundException { return o.readObject(in); } } }
なんてのを書いて、カスタムクラスローダでロードする class の方を interface ObjectLoader の実装にしておいてそれを引数で渡す。
public class Bar implements Foo.ObjectLoader public Object readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { return in.readObject(); } public void do() { : : Object o = Foo.loadObject(this, in); //※ : : } }
抜粋するとこんな感じかな(これでコンパイル通るのか?)。
追記
これだと例になってないや。
こんな面倒な仕掛けをする必要が無いところ(※)でデシリアライズしてるもんなぁ。
*1 実行スタックはわざと例外を起こして Exception#printStackTrace() を見ると確認できる。