2
Serializable
を実装していても正しくシリアル化できないライブラリクラスがあります。修正できませんが、回避策としてObjectOutputStream
とObjectInputStream
を拡張できます。java特定のクラスのインスタンスごとに追加データを書き込むためのObjectOutputStreamをカスタマイズする
私は私のObjectOutputStream
がA
が直列化復元された後、そのデータを読み込み、適用するクラスA
とObjectInputStream
の各インスタンスの追加データを書きたいです。
現在、私はwriteObject()
とreadObject()
への明示的な追加の呼び出しを必要とする中間的な回避策があります。私はこれらの呼び出しなしで管理することを好むでしょう。
どのように動作するかを見るにはコメントを外します。
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import org.junit.Test;
import static org.junit.Assert.*;
public class CloneSerializableTest2 {
// library classes
public static class A implements Serializable {
public transient String s1;
}
public static class MyA extends A {
public String s2;
}
/*
private static class AHolder implements Serializable {
private static final Field s1Fld;
static {
try {
s1Fld = A.class.getDeclaredField("s1");
s1Fld.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private String s1;
private A a;
public AHolder(A m) {
this.a = m;
try {
s1 = (String)s1Fld.get(m);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
public void restoreA() {
try {
s1Fld.set(a, s1);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
}
*/
@SuppressWarnings("unchecked")
public static <T> T cloneSerializable(T o) {
try {
/*
final List<AHolder> accumSrc = new ArrayList<AHolder>();
*/
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout)
/*
{
{
enableReplaceObject(true);
}
@Override
protected Object replaceObject(Object obj) throws IOException
{
if (obj instanceof A) {
accumSrc.add(new AHolder((A)obj));
}
return super.replaceObject(obj);
}
}
*/
;
out.writeObject(o);
/*
out.writeObject(accumSrc);
*/
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object copy = in.readObject();
/*
List<AHolder> accumDst = (List<AHolder>)in.readObject();
for (AHolder r : accumDst) {
r.restoreA();
}
*/
in.close();
return (T)copy;
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected error", e);
}
}
@Test
public void testIt() throws Exception {
try {
MyA m1 = new MyA();
m1.s1 = "a";
m1.s2 = "b";
m1 = cloneSerializable(m1);
assertEquals("a", m1.s1);
assertEquals("b", m1.s2);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
なぜあなたは正しくないクラスにパッチを適用することはできませんか? –
実生活では一時的なフィールドがプライベートなので、私は反射が必要です。 "A"は自分自身のフィールドを持つ子孫を持つ可能性があり、これらはすべて適切に処理されなければならないことに注意してください。 – basin
Peter:ライブラリ内にあるため – basin