ClassCastException when Appending Object OutputStream

后端 未结 3 2019
伪装坚强ぢ
伪装坚强ぢ 2020-12-09 14:00

I have been trying to do a little project that needs an appendable ObjectOutputStream. I have gone through a couple of solutions and i found this It seemed to solve my probl

相关标签:
3条回答
  • 2020-12-09 14:13

    No clear answer for you, but some thoughts and things to try:

    • The stack trace includes at java.util.ArrayList.readObject(Unknown Source), which indicates the problem occurs while deserializing a class containing an ArrayList. Narrow your problem down by commenting out the private ArrayList<Transaction> transactions;

    • Do you have the same problem if you generate a single file without using your appender? If so, create two forms of the same content: one with appender, one without. Diffs?

    • I do see one other reference to a similar problem, no solution. Also uses the same appender: Serialization/deserialization ClassCastException: x cannot be cast to java.io.ObjectStreamClass

    0 讨论(0)
  • 2020-12-09 14:15

    The problem here is that the previous poster who gave you an appendable ObjectOutputStream led you astray. An ObjectOutputStream/ObjectInputStream tries to store each object only once, and then later refer back to the object already stored. That is, in the stream you can end up with something like this if you have a bunch of objects of the same class:

    CLASS_1_DESCRIPTION
    OBJECT_1
    REF_TO_CLASS_1
    OBJECT_2
    REF_TO_CLASS_1
    OBJECT_3
    ...
    

    When an ObjectInputStream is converting the stream back into a bunch of objects, it maintains a list of what things it's already deserialized. The error it's telling you is that it was trying to deserialize an object, read what should have been a reference to the description of the object's class, but when it looked up that reference in its internal table it saw a String. Quite naturally, it blew up.

    I think the fix is as simple as this - in your AppendableObjectOutputStream, change this method:

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

    the reset() method in ObjectOutputStream inserts a marker into the stream saying "throw away all the state at this point". Then, when you read this back in with a ObjectInputStream, the input stream's idea of what's been deserialized will match what the output stream thought the state was when it deserialized the stuff in the first place.

    (EDIT: Answer question from comments)

    The only detrimental consequences of this that I can think of:

    • The final file will be longer than it would have been if you'd written everything all to one ObjectOutputStream, especially if the same Profile object appears multiple times. Even if not, you'll repeat class descriptors in the stream, so lots of repetitions of {open AppendableObjectOutputStream, write one object, close stream} could bloat the file size a bit.

    • Related to that, after you deserialize everything you may end up with multiple copies of what should have been the identical object. For example, suppose you write a bunch of things including some PPRestrictedAccount objects, then close the stream, open it as an AppendableObjectOutputStream, and write out a PPBusinessAccount that has in its operators list some of the PPRestrictedAccounts you wrote out earlier. When you read all that back in, the PPRestrictedAccounts you read initially won't be the same objects (that is, they won't be ==) to the PPRestrictedAccounts that you find in the PPBusinessAccount's operators list. They'll be instantiated separately. To avoid this, you'd need to de-duplicate them with a readResolve method. Everything that was written to a single AppendableObjectOutputStream instance will be connected correctly however. Depending on your application, this might not be something to worry about at all.

    In terms of will-this-blow-up-or-not safety, this is as safe as any other use of java serialization; there isn't anything specific about your classes that makes it work. Just be aware that any object written in multiple separate openings of the output file will be deserialized as separate copies of the original object. (Absent any readResolve magic)

    0 讨论(0)
  • 2020-12-09 14:19

    Try it like this....

    readObject() returns the objects of type Object, so you need to explicitly cast them into its original types...

    Eg:

    PPAccount pa = (PPAccount) readObject();

    0 讨论(0)
提交回复
热议问题