2012-09-05 9 views
5

追加可能なObjectOutputStreamが必要な小さなプロジェクトを実行しようとしています。 私は解決策のカップルを通過し、私が見つけたthisそれは私の問題を最初に解決するようだ。しかし、私のプロジェクトのさらなる発展に伴い、私は予期しない例外が発生し始めました。 以下は私のクラスです。私が観察している何オブジェクトの出力ストリームを追加するときのClassCastException

public class PPAccount implements Serializable 
{ 
    private Profile profile; 
    private String email; 
    private float accountBal; 
    private boolean isActivated; 
    private String activationCode; 
    private ArrayList<Transaction> transactions; 

    //a few functions 
} 
public class PPRestrictedAccount extends PPAccount { 
    private String parentEmail; 
    private float withdrawLimit; 

     //a few functions 
} 
public class PPBusinessAccount extends PPAccount { 
    private ArrayList <PPRestrictedAccount> accountOperators; 

     //a few functions 
} 
public class PPStudentAccount extends PPAccount { 
    private String parentEmail; 

     //a few functions 
} 

は私がしたObjectOutputStreamをオーバーライドして、私は、ファイルにオブジェクトを追加していながら、それを使用しているthisを使用して、あります。しかし、どうすればいいですか?私が書いているのは、

PPBusinessAccountです。最初に何度も何度も繰り返していきます。そして、PPAccountを書いてください。 PPAccount最初に、繰り返し....次にPPBusinessAccountを書いて、PPAccountと書いてください。それはよく書いていますが、読んでいる間に私はClassCastExceptionになります。

クラスをキャストするのを避けるために、Objectクラスのインスタンスに直接オブジェクトを読み込んで保存しようとしましたが、まだreadObject()がスローされますClassCastExceptionです。

私は自分のシナリオを説明するのに最善を尽くしました。何も得られないかどうかを教えてください。なぜこうなった??これは初めてのために書いているヘッダーとは何か関係がありますか?ベースクラスの行に沿ってヘッダは子クラスをサポートできませんか?ターンアラウンドは何ですか?

私はこのようなキャストをしています:writeAccountがストリームに書き込みながら

java.lang.ClassCastException: java.lang.String cannot be cast to java.io.ObjectStreamClass 
    at java.io.ObjectInputStream.readClassDesc(Unknown Source) 
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source) 
    at java.io.ObjectInputStream.readClassDesc(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 
    at java.util.ArrayList.readObject(Unknown Source) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at java.io.ObjectStreamClass.invokeReadObject(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source) 
    at java.io.ObjectInputStream.readSerialData(Unknown Source) 
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
    at java.io.ObjectInputStream.readObject0(Unknown Source) 
    at java.io.ObjectInputStream.readObject(Unknown Source) 
    at in.msitprogram.iiit.paypal.persistance.DataStore.lookupAccount(DataStore.java:50) 
    at in.msitprogram.iiit.paypal.persistance.DataStore.writeAccount(DataStore.java:131) 
    at in.msitprogram.iiit.paypal.console.PPNewAccountScreen.show(PPNewAccountScreen.java:78) 
    at in.msitprogram.iiit.paypal.console.MainMenu.show(MainMenu.java:42) 
    at in.msitprogram.iiit.paypal.PPSystem.main(PPSystem.java:17) 
Exception in thread "main" java.lang.NullPointerException 
    at in.msitprogram.iiit.paypal.persistance.DataStore.lookupAccount(DataStore.java:66) 
    at in.msitprogram.iiit.paypal.persistance.DataStore.writeAccount(DataStore.java:131) 
    at in.msitprogram.iiit.paypal.console.PPNewAccountScreen.show(PPNewAccountScreen.java:78) 
    at in.msitprogram.iiit.paypal.console.MainMenu.show(MainMenu.java:42) 
    at in.msitprogram.iiit.paypal.PPSystem.main(PPSystem.java:17) 

lookUpAccountストリームから読み込むスタックトレース

Object o = ois.readObject();  //Surprisingly exception is raised here (line:50 in DataStore) 
PPAccount ppa = (PPAccount)o; 

、ここでのコードは次のとおりです。

public static PPAccount lookupAccount(String email) throws IOException, ClassNotFoundException 
    { 
     PPAccount account = null; //initialize it after reading from file 
     // write code to open the files, read 
     PPAccount foundAccount=null; 
     ObjectInputStream ois=null; 
     FileInputStream fis=null; 
     File ff = new File(PPConstants.AllAccountDetails); 
     if(!ff.exists()) 
     { 
      //System.out.println("Required file not found"); 
      return null; 
     } 
     try 
     { 
      fis=new FileInputStream(PPConstants.AllAccountDetails); 
      ois = new ObjectInputStream(fis); 
      while(fis.available()>0 && foundAccount==null) 
      { 
       //Object o=null; 
       PPAccount ppa=null; 
       try 
       { 
        ppa = (PPAccount)ois.readObject(); 
        if(ppa==null) 
         return null; 
        System.out.println(ppa); 
       } 

       catch(ClassCastException cce) 
       { 
        System.out.println("Class cast exception "+cce.getCause()); 
        cce.printStackTrace(); 
       } 
       if(email.equals(ppa.getEmail())) 
       { 
        foundAccount=ppa; 
        break; 
       } 
       if(ppa instanceof PPBusinessAccount) 
       { 
        PPBusinessAccount ppba = (PPBusinessAccount)ppa; 
        ArrayList<PPRestrictedAccount> alist=ppba.getAccountOperators(); 
        if(alist==null) 
         continue; 
        Iterator<PPRestrictedAccount> it = alist.iterator(); 
        while(it.hasNext()) 
        { 
         PPRestrictedAccount ppr=(PPRestrictedAccount) it.next(); 
         System.out.println(ppr); 
         if(email.equals(ppr.getEmail())) 
         { 
          foundAccount = ppr; 
          break; 
         } 
        }//iterators while loop 
       }//if it is a businessAccount 
      }//outer while 
     }//try 
     finally 
     { 
      if(ois!=null) 
       ois.close(); 
      if(fis!=null) 
       fis.close(); 
     } 
     return foundAccount; 
    } 
    public static void writeAccount(PPAccount account,Boolean append) throws IOException, ClassNotFoundException, DuplicateAccountException 
    { 
     ObjectOutputStream oos=null; 
     FileOutputStream fos=null; 
     try 
     { 
      if(!append) 
      { 
       fos= new FileOutputStream(PPConstants.AllAccountDetails); 
       oos = new ObjectOutputStream(fos); 
       //System.out.println("Not Appending"); 
       oos.writeObject(account); 
      } 
      else 
      { 
       File ff = new File(PPConstants.AllAccountDetails); 
       if(!ff.exists()) 
       { 
        System.out.println("Required file not found"); 
        return; 
       } 
       PPAccount aa=lookupAccount(account.getEmail()); 
       if(aa!=null) 
        throw new DuplicateAccountException("An Account already exits with this email-ID"); 
       oos = new AppendingObjectOutputStream(new FileOutputStream(PPConstants.AllAccountDetails,append)); 
       oos.writeObject(account); 
      } 
     } 
     finally 
     { 
      if(oos!=null) 
       oos.close(); 
      if(fos!=null) 
       fos.close(); 
     } 

    } 
+0

例外トレースも投稿できますか?それはまた間違っていることの明確な手がかりを与える... – SiB

+0

あなたはストリームに何かを書いていますか?たとえば、writeObject()以外のメソッドを使用していますか? – EJP

+0

@EJPいいえ、ストリームに他に何も書いていません。これらのクラスのいずれかを書き込む唯一のメソッドである 'writeObject()'以外です。 – sasidhar

答えて

11

ここでの問題はあなたに追記ObjectOutputStreamを与えた以前のポスターは道に迷ってあなたを導いたということです。また、同じアペンダを使用しています。 ObjectOutputStream/ObjectInputStreamは、各オブジェクトを1回だけ格納し、後ですでに格納されているオブジェクトを参照しようとします。それはあなたが同じクラスのオブジェクトの束持っている場合は、このようなもので終わることができたストリームでは、次のとおりです。ObjectInputStreamは、オブジェクトの束に戻すストリームに変換され

CLASS_1_DESCRIPTION 
OBJECT_1 
REF_TO_CLASS_1 
OBJECT_2 
REF_TO_CLASS_1 
OBJECT_3 
... 

を、それが維持すでにデシリアライズされているもののリスト。それはあなたがオブジェクトを逆シリアル化しようとしていたこと、オブジェクトのクラスの記述への参照であったはずのものを読んでいるということですが、内部テーブルの参照を参照すると、Stringが見えます。当然、それは爆破した。

私は修正プログラムは、このような単純なだと思う - あなたのAppendableObjectOutputStreamに、この方法に変更:「この時点ですべての状態を捨てると言っストリームにObjectOutputStream挿入マーカーで

@Override 
    protected void writeStreamHeader() throws IOException { 
    // do not write a header, but reset the handle list 
    reset(); 
    } 

reset()方法を"次に、ObjectInputStreamでこれを読み込むと、入力ストリームのデシリアライズされたアイデアは、出力ストリームが状態を最初にデシリアライズしたと思っていたものと一致します。

(EDIT:コメントから回答質問)私は考えることができる。この

だけ有害な結果:

  • 最終的なファイルは、あなたがしたい場合、それはあったであろうよりも長くなりますすべてObjectOutputStreamにすべてを書きました。特に同じProfileオブジェクトが複数回出現した場合そうでない場合でも、ストリーム内でクラス記述子を繰り返すので、{open AppendableObjectOutputStreamを開いて、1つのオブジェクトを書き込む、ストリームを閉じる}の繰り返しが多いため、ファイルサイズが少し大きくなる可能性があります。

    これに関連して、すべてをデシリアライズした後は、同じオブジェクトであったはずのものを複数コピーすることになります。たとえば、PPRestrictedAccountオブジェクトを含むたくさんのオブジェクトを作成し、ストリームを閉じてAppendableObjectOutputStreamとして開き、operatorsに先に書き込んだものの一部をリストしたPPBusinessAccountを書き出します。最初に読み込んだPPRestrictedAccountは、のoperatorsリストにあるPPRestrictedAccountと同じオブジェクトではありません(つまり、==ではありません)。それらは別々にインスタンス化されます。これを避けるには、readResolveメソッドを使用して重複を解除する必要があります。しかし、単一のAppendableObjectOutputStreamインスタンスに書き込まれたものはすべて正しく接続されます。アプリケーションによっては、まったく心配するものではないかもしれません。

安全性の面では、これはJavaシリアル化の他の用途と同じくらい安全です。クラスを動作させるための具体的なことは何もありません。出力ファイルの複数の別々の開口部に書き込まれたオブジェクトは、元のオブジェクトの別々のコピーとしてデシリアライズされることに注意してください。 (何もないreadResolve魔法)

+0

'Perfect'これを修正するのが常だったのですが、解決策は1行です。ありがとう。私は明日の答えと恩恵を受け入れます。私は、「この時点で国家を捨てる」が安全かどうかを知ることに興味がありますか?解決策は私にとってはうまくいった。しかし、これを一般的なケースシナリオに適用する。それはすべてのシナリオでソリューションを安全にするでしょうか? – sasidhar

+0

質問に答えるために編集されたメインポスト。 –

0

このように試してください....

readObject()あなたは、元のタイプにそれらをキャスト明示的に必要なので...、

例:タイプObjectobjectsを返します。

PPAccount pa = (PPAccount) readObject();

+0

私の質問を編集しました – sasidhar

+0

@sasidharを試してください 'PPAccount ppa =(PPAccount)ois.readObject();' –

+0

これは元のコードです。例外がどこにあるかを明確にするために、 'readObject ) 'メソッドがエラーをスローしています。なぜ私は理解できないのですか? – sasidhar

0

明確にあなたに答えてください、しかしいくつかの考えと試してみましょう:

  • at java.util.ArrayList.readObject(Unknown Source)を含むスタックトレースは、ArrayListを含むクラスを逆シリアル化する際に問題が発生したことを示します。 private ArrayList<Transaction> transactions;

  • をコメントアウトして、問題を絞り込み、あなたのアペンダを使用してせずに、単一のファイルを生成する場合は、同じ問題を持っていますか?その場合は、同じコンテンツの2つのフォームを作成します:1つはアペンダー付きで、もう1つはアペンダーなしです。 Diffs?

  • 私は同様の問題を解決するための参照を参照してください。 Serialization/deserialization ClassCastException: x cannot be cast to java.io.ObjectStreamClass

+0

*アペンダーなしで*を使用しているときに問題に直面していません。そして、ストリームに読み書きすることもできますが、特定の順序でのみ行うことができます。もし書き込まれる最初のクラスが 'PPBusinessAccount'であれば、全てがうまくいくようです。 ArrayListが犯人である場合、それは正しく順序が違うでしょうか?とにかく、配列リストを削除し、nullにすることでテストします。結果はそれほど変わらなかった。 – sasidhar

+0

これで、瞬間のノイズを最小限に抑えるためにArrayListをそのまま残しましょう。最初の後のオブジェクトごとにアペンダーを使用して、(b)アペンダーをまったく使用せずにファイル(a)「PBAccount、PBAccount、PBAccount、PBBusinessAccount」を生成できますか? 2つのファイルに対して 'diff'を実行します。 –

関連する問題