2012-09-05 12 views
5

में भाग लेने पर क्लासकास्ट अपवाद जब मैं एक छोटी परियोजना करने की कोशिश कर रहा हूं जिसके लिए एक अटैचमेंट ऑब्जेक्टऑटपुटस्ट्रीम की आवश्यकता है। मैं कुछ समाधानों से गुज़र चुका हूं और मुझे this मिला है, यह पहली बार मेरी समस्या का समाधान करना प्रतीत होता था। लेकिन मेरे प्रोजेक्ट के आगे के विकास पर मुझे अप्रत्याशित अपवाद मिलना शुरू हो गया। निम्नलिखित मेरी कक्षाएं हैं।ऑब्जेक्ट आउटपुटस्ट्रीम

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 
} 

मैं क्या देखा है this मैं ObjectOutputStream अधिरोहित और इसका इस्तेमाल जब मैं फाइल करने के लिए वस्तुओं जोड़कर रहा है का उपयोग कर, है। लेकिन क्या होता है यदि मैं लिखता हूं:

PPBusinessAccount पहले, किसी भी समय दोहराएं ... फिर PPAccount लिखें सब ठीक है। PPAccount पहले, दोहराना .... फिर PPBusinessAccount लिखें, फिर PPAccount लिखें, यह अच्छी तरह से लिखता है लेकिन पढ़ने के दौरान मुझे ClassCastException मिलता है।

कक्षाओं से बचने के लिए ऑब्जेक्ट्स पढ़ने और उन्हें सीधे Object कक्षा के उदाहरण में संग्रहीत करने की कोशिश की गई है लेकिन अभी भी readObject()ClassCastException फेंकता है।

मैंने अपने परिदृश्य का वर्णन करने के लिए सबसे अच्छा प्रयास किया, बताओ कि आपको कुछ भी नहीं मिला है। ये क्यों हो रहा है?? क्या इसे हेडर के साथ कुछ करने के लिए मिला है जो यह पहली बार लिख रहा है ?? बेस क्लास हेडर की लाइनों के साथ बाल वर्ग का समर्थन नहीं कर सकता ?? चारों ओर मोड़ क्या है?

मैं इस तरह डाली कर रहा हूँ:

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

स्टैक ट्रेस

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 धारा से पढ़ता है, जबकि writeAccount, धारा के लिए लिखते हैं यहाँ कोड है:

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

समस्या यहां है कि पिछले पोस्टर जो आप एक appendable ObjectOutputStream दिया आप भटक नेतृत्व है: इसके अलावा एक ही appender का उपयोग करता है। एक ObjectOutputStream/ObjectInputStream प्रत्येक ऑब्जेक्ट को केवल एक बार स्टोर करने का प्रयास करता है, और उसके बाद बाद में संग्रहीत ऑब्जेक्ट को वापस संदर्भित करता है। यही कारण है, धारा में अगर आप एक ही कक्षा की वस्तुओं का एक समूह है कुछ इस तरह से खत्म कर सकते हैं:

CLASS_1_DESCRIPTION 
OBJECT_1 
REF_TO_CLASS_1 
OBJECT_2 
REF_TO_CLASS_1 
OBJECT_3 
... 

जब एक ObjectInputStream वस्तुओं का एक समूह में वापस धारा परिवर्तित करने की है, यह कहना है एक क्या चीजें पहले से ही deserialized की सूची है। यह त्रुटि आपको बता रही है कि यह किसी ऑब्जेक्ट को deserialize करने का प्रयास कर रहा था, पढ़ें कि ऑब्जेक्ट की कक्षा के विवरण का संदर्भ क्या होना चाहिए था, लेकिन जब उसने अपनी आंतरिक तालिका में उस संदर्भ को देखा तो इसे String देखा गया। काफी स्वाभाविक रूप से, यह उड़ा दिया।

मुझे लगता है कि ठीक इस के रूप में सरल है - अपने AppendableObjectOutputStream में, इस विधि को बदलें:

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

ObjectOutputStream में reset() विधि धारा में एक मार्कर कहा, "इस बिंदु पर सभी राज्य फेंक सम्मिलित करता है "। फिर, जब आप इसे ObjectInputStream के साथ वापस पढ़ते हैं, तो इनपुट स्ट्रीम का क्या वर्णन किया गया है, इसका विचार यह होगा कि आउटपुट स्ट्रीम ने राज्य को सोचा था कि जब यह पहली जगह में सामान को खराब कर देता था।

(संपादित करें: टिप्पणियों से प्रश्न का उत्तर दें)

इस का केवल हानिकारक परिणाम है कि मैं के बारे में सोच सकते हैं:

  • अंतिम फ़ाइल लंबे समय तक हो जाएगा की तुलना में यह अगर तुम चाहते हो गया होता सब कुछ एक ObjectOutputStream पर लिखा, खासकर अगर Profile ऑब्जेक्ट कई बार प्रकट होता है। यहां तक ​​कि यदि नहीं, तो आप स्ट्रीम में कक्षा डिस्क्रिप्टर दोहराएंगे, इसलिए {खुले AppendableObjectOutputStream की एक दोहराव, एक ऑब्जेक्ट लिखें, करीबी स्ट्रीम} फ़ाइल आकार को थोड़ा सा फूट सकता है।

  • इससे संबंधित, आप सब कुछ deserialize के बाद आप एक ही वस्तु के समान प्रतियों के साथ कई प्रतियों के साथ खत्म हो सकता है। उदाहरण के लिए, मान लीजिए कि आप कुछ PPRestrictedAccount ऑब्जेक्ट्स सहित चीजों का एक समूह लिखते हैं, फिर स्ट्रीम को बंद करें, इसे AppendableObjectOutputStream के रूप में खोलें, और PPBusinessAccount लिखें जो operators में PPRestrictedAccount में से कुछ सूचीबद्ध है जो आपने पहले लिखा था। जब आप उन सभी को वापस पढ़ते हैं, तो PPRestrictedAccount एस आप प्रारंभ में पढ़ते हैं, वही ऑब्जेक्ट्स नहीं होंगे (यानी, वे == नहीं होंगे) PPRestrictedAccount पर आपको PPBusinessAccount की operators सूची में मिलती है। उन्हें अलग से तत्काल किया जाएगा। इससे बचने के लिए, आपको readResolve विधि के साथ उन्हें डुप्लिकेट करना होगा। सब कुछ जो एक AppendableObjectOutputStream उदाहरण पर लिखा गया था, ठीक से जोड़ा जाएगा। आपके आवेदन के आधार पर, यह चिंता करने के लिए कुछ भी नहीं हो सकता है।

इच्छा-इस-उड़ा-या-सुरक्षा के मामले में, यह जावा क्रमबद्धता के किसी भी अन्य उपयोग के रूप में सुरक्षित है; आपकी कक्षाओं के बारे में कुछ भी विशिष्ट नहीं है जो इसे काम करता है।बस जागरूक रहें कि आउटपुट फ़ाइल के कई अलग-अलग खोलने में लिखे गए किसी भी ऑब्जेक्ट को मूल ऑब्जेक्ट की अलग-अलग प्रतियों के रूप में deserialized किया जाएगा। (अनुपस्थित किसी भी readResolve जादू)

+0

'बिल्कुल सही' हर बार मैंने इसे ठीक करने में बिताया, समाधान एक पंक्ति है। धन्यवाद। मैं कल जवाब और बक्षीस स्वीकार करूंगा। मुझे यह जानने में दिलचस्पी है, अगर 'इस बिंदु पर राज्य को फेंकना' सुरक्षित है या नहीं? समाधान मेरे लिए काम किया, ठीक है। लेकिन इसे एक सामान्य मामले परिदृश्य में लागू करना। क्या यह समाधान सभी परिदृश्यों में सुरक्षित बनाएगा ?? – sasidhar

+0

प्रश्न का उत्तर देने के लिए मुख्य पोस्ट संपादित किया गया। –

0

इसे इस तरह से आजमाएं ....

readObject()की objects प्रकारObject देता है, ताकि आप उन्हें अपने मूल प्रकार में डाला स्पष्ट करने की जरूरत है ...

उदाहरण के लिए:

PPAccount pa = (PPAccount) readObject();

+0

मेरा प्रश्न संपादित करें कृपया देखें – sasidhar

+0

@ ससीधर 'पीपीएकाउंट पीपीए = (पीपीएसीसीएटी) ओआईएस.readObject(); ' –

+0

जो मूल कोड है, स्पष्ट करने के लिए, अपवाद कहां है, मैं इसे इस तरह बदलता हूं,' readObject () 'विधि त्रुटि फेंक रहा है। मुझे समझ में नहीं आता क्यों? – sasidhar

0

कोई स्पष्ट आपके लिए जवाब, लेकिन कुछ विचार और चीजों को आजमाएं:

  • स्टैक ट्रेस में at java.util.ArrayList.readObject(Unknown Source) शामिल है, जो इंगित करता है कि समस्या ArrayList वाली कक्षा को deserializing करते समय होती है। बाहर टिप्पणी private ArrayList<Transaction> transactions;

  • आप एक ही समस्या है अगर आप अपने appender का उपयोग किए बिना एक एकल फाइल उत्पन्न अपनी समस्या को सीमित करें? यदि ऐसा है, तो उसी सामग्री के दो रूप बनाएं: एक एपेंडर के साथ, बिना किसी के। Diffs?

  • मुझे एक समान समस्या का कोई अन्य संदर्भ नहीं है, कोई समाधान नहीं। Serialization/deserialization ClassCastException: x cannot be cast to java.io.ObjectStreamClass

+0

* बिना * एपेंडर का उपयोग करते समय मुझे कोई समस्या नहीं आ रही है। और कृपया ध्यान दें कि मैं स्ट्रीम में पढ़ने और लिखने में भी सक्षम हूं, लेकिन केवल विशिष्ट क्रम में। यदि पहली कक्षा लिखी जानी है तो 'PPBusinessAccount' सब कुछ ठीक काम करने लगता है। यदि ArrayList अपराधी है तो यह एक अलग क्रम में भी असफल होना चाहिए? किसी भी तरह से सरणी सूची को हटाकर और इसे शून्य बनाकर परीक्षण किया जाता है। परिणाम कोई अलग नहीं थे। – sasidhar

+0

ठीक है, तो चलिए इस पल के लिए शोर को कम करने के लिए ArrayList को छोड़ दें। क्या आप पहली बार प्रत्येक ऑब्जेक्ट के लिए एपेंडर का उपयोग करके फ़ाइल (ए) "पीबीएसीसीउंट, पीबीएकाउंट, पीबीएकाउंट, पीबी बिजनेस अकाउंट" उत्पन्न कर सकते हैं, और (बी) एपेंडर का उपयोग किए बिना। दो फाइलों पर 'diff' चलाएं। –

संबंधित मुद्दे