2012-02-07 6 views
2

Serializableを実装していても正しくシリアル化できないライブラリクラスがあります。修正できませんが、回避策としてObjectOutputStreamObjectInputStreamを拡張できます。java特定のクラスのインスタンスごとに追加データを書き込むためのObjectOutputStreamをカスタマイズする

私は私のObjectOutputStreamAが直列化復元された後、そのデータを読み込み、適用するクラスAObjectInputStreamの各インスタンスの追加データを書きたいです。

現在、私は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; 
     } 
    } 
} 
+0

なぜあなたは正しくないクラスにパッチを適用することはできませんか? –

+0

実生活では一時的なフィールドがプライベートなので、私は反射が必要です。 "A"は自分自身のフィールドを持つ子孫を持つ可能性があり、これらはすべて適切に処理されなければならないことに注意してください。 – basin

+0

Peter:ライブラリ内にあるため – basin

答えて

0

自分自身に答える

import java.io.*; 
import java.lang.reflect.Field; 
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, Externalizable { 
     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; 

     @SuppressWarnings("unused") 
     public AHolder() { 
     } 
     public AHolder(A m) { 
      this.a = m; 
      try { 
       s1 = (String)s1Fld.get(m); 
      } catch (IllegalAccessException e) { 
       throw new RuntimeException("Unexpected error", e); 
      } 
     } 

     private Object readResolve() { 
      try { 
       s1Fld.set(a, s1); 
      } catch (IllegalAccessException e) { 
       throw new RuntimeException("Unexpected error", e); 
      } 
      return a; 
     } 

     @Override 
     public void writeExternal(ObjectOutput out) throws IOException { 
      out.writeObject(s1); 
      ObjectOutputStream out2 = ((ObjectOutputStream)out); 
      out2.writeUnshared(a); 
     } 

     @Override 
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
      s1 = (String)in.readObject(); 
      a = (A)in.readObject(); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    public static <T> T cloneSerializable(T o) { 
     try { 

      ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
      ObjectOutputStream out = new ObjectOutputStream(bout) 
      { 
       { 
        enableReplaceObject(true); 
       } 
       @Override 
       protected Object replaceObject(Object obj) throws IOException 
       { 
        if (obj instanceof A) { 
         obj = new AHolder((A) obj); 
        } else if (obj instanceof AHolder) { 
         obj = ((AHolder)obj).a; 
        } 
        return super.replaceObject(obj); 
       } 
      }; 

      out.writeObject(o); 

      out.close(); 
      ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); 
      ObjectInputStream in = new ObjectInputStream(bin); 
      Object copy = in.readObject(); 

      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; 
     } 
    } 
} 
関連する問題