This discussion is archived
10 Replies Latest reply: Sep 27, 2012 5:16 PM by EJP RSS

Serialization error - apparently unusual

942608 Newbie
Currently Being Moderated
Hello,



I have a java application entirely local to one machine. There are a couple of arrayLists that hold objects used in many places. I need to save them (the contents of the Containers) to disk, reload them, keep different versions, etc. (The objects are shallow and simple in terms of inheritance etc, and hold fields of primitive data types, and an arrayList of int2, for example.)

Serialization works 95% of the time, perfectly (that is, when it works, it does exactly as it should.) I used code from one of the tutorials, and it was easy to set up (quoted below).

When it fails, it fails when trying to de-serialize the disk file data. It always fails in this process - but, as I say, 5% of the times I run the program.

Having read every relevant post I could find, I am aware that one must not change the classes involved with the serialized objects - and I don't. I have also tried hard-coding the serialVersionUID. The books I have go into the kind of serialization code I use, but don't discuss this pitfall.

One way to make it fail is either 1) to declare or 2)to remove a declaration of a file handle globally - that is, above/outside 'main', or inside main. At first I wrote a snippet at the beginning of main to open an extant textfile, which worked fine, as usual; I discovered that the only thing required to cause the problem was

public static File g; (if not in main)
File g = new File(textfile.txt); (in main)

Its inclusion, or its removal, causes the failure to de-serialize. Apparently declaring (or un-declaring) an unrelated text file changes something. Other things can cause the same problem, but what those things were was ambiguous.

I could use guidance about useful diagnostics, and opinions about the cause/fix. If anyone has any ideas I'll try to post more of the relevant code. Unfortunately, the serialization code is boilerplate (see below), and the problem is in some aspect of the whole program. BTW I happen to be using NetBeans.

Here's a bit of info. This is the exception that gets thrown, and a quote from Oracle about it:

InvalidClassException (full stack trace below)

Thrown when a class cannot be used to restore objects for any of these reasons:
The class does not match the serial version of the class in the stream.
The class contains fields with invalid primitive data types.
The Externalizable class does not have a public no-arg constructor.
The Serializable class can not access the no-arg constructor of its closest non-Serializable superclass.

I am pretty sure I haven't broken any of these rules.

This is from oracle docs:

Note - It is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail.


THANKS!
Chris lanz

start massLoadAxis. ← my method
the error occurs on this line: record = (ReqAxesObj)in.readObject();

java.io.InvalidClassException: wdaxwns.Primitives; local class incompatible: stream classdesc serialVersionUID = 2598607360480639650, local class serialVersionUID = -50536690600245192

     at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)

     at wdaxwns.Primitives.massLoadAxis(Primitives.java:782)
     at wdaxwns.WdAx.firstInit(WdAx.java:217)
     at wdaxwns.WdAx.main(WdAx.java:90)
java.io.InvalidClassException: wdaxwns.Primitives; local class incompatible: stream classdesc serialVersionUID = 2598607360480639650, local class serialVersionUID = -50536690600245192
     at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
     at wdaxwns.Primitives.massLoadWord(Primitives.java:822)
     at wdaxwns.WdAx.firstInit(WdAx.java:218)
     at wdaxwns.WdAx.main(WdAx.java:90)


Here is the code that serializes (in this case, writing the contents of the arrayList “allWords_ary”)

public static void dumpFile()
throws IllegalArgumentException {


// "allWords.ser" is the file itself
// "allWords_ary" is the internal arrayList that gets filled & dumped

filename = "serial/allWords.ser";


FileOutputStream fos = null;
ObjectOutputStream out = null;
int count = 0;
try {
fos = new FileOutputStream(filename);
out = new ObjectOutputStream( fos );

for ( word w : allWords_ary ) {
out.writeObject( w );
//out.flush();
System.out.print(".");
count++;
}

out.close();
} catch(IOException ex){ ex.printStackTrace(); }


AND HERE IS THE CORRESPONDING DE_SERIALIZATION


public static void massLoadWord(String filename)
throws IOException, FileNotFoundException {
System.out.println("Now read into allWords_ary from file...");
int count = 0;
word record = null;
FileInputStream fis = null;
ObjectInputStream in = null;
try {
fis = new FileInputStream(filename);
in = new ObjectInputStream( fis );

record = (word)in.readObject();
// quit this loop via EOF exception
while ( record != null ){
allWords_ary.add( record );
System.out.print(".");
count++;

record = (word)in.readObject(); ← THIS IS WHERE IT FAILS (?)
}

} catch(EOFException ex) {
System.out.println("Caught EOFexcep");
// ex.printStackTrace();
in.close();
}
catch(IOException ex){ ex.printStackTrace(); }
catch(ClassNotFoundException ex) { ex.printStackTrace();  }

}
  • 1. Re: Serialization error - apparently unusual
    jtahlborn Expert
    Currently Being Moderated
    Note, cross-posted here:

    http://stackoverflow.com/questions/12574647/java-serialization-glitch-but-not-the-usual-ones#comment16941911_12574647
  • 2. Re: Serialization error - apparently unusual
    jtahlborn Expert
    Currently Being Moderated
    clanz wrote:
    Having read every relevant post I could find, I am aware that one must not change the classes involved with the serialized objects - and I don't. I have also tried hard-coding the serialVersionUID. The books I have go into the kind of serialization code I use, but don't discuss this pitfall.
    yes you do change it. adding/removing the static File reference changes the "default" serialVersionUID. even though static values are not serialized, the default serialVersionUID algorithm must be sensitive to those changes.

    this is a usual serialization problem, and the solution is very simple: use explicit serialVersionUIDs in your serialized objects. (which is a best practice anyway, as almost any java IDE these days will warn you about missing serialVersionUIDs in Serializable classes).
  • 3. Re: Serialization error - apparently unusual
    942608 Newbie
    Currently Being Moderated
    Hello,

    Thanks for responding.

    I'm sorry, I mis-spoke. When I said "I don't change the serializable classes" I should have said "The failure occurs without making any changes to the code in serializable classes"

    I have already explicitly declared the serialVersionUID in each serializable class, and it made no difference. It's possible I'm doing it wrong, though: I took it literally when the oracle docs said to use explicit UIDs in every serializable class, and so I put their line in each class:

    private static final long serialVersionUID = 15L;

    I gave each class a different longint value. From what I've read this seems to be the thing to do, but I'm still uncertain.

    I hope I didn't misunderstand your reply.

    Thanks again

    c lanz
  • 4. Re: Serialization error - apparently unusual
    jtahlborn Expert
    Currently Being Moderated
    clanz wrote:
    I have already explicitly declared the serialVersionUID in each serializable class, and it made no difference. It's possible I'm doing it wrong, though: I took it literally when the oracle docs said to use explicit UIDs in every serializable class, and so I put their line in each class:

    private static final long serialVersionUID = 15L;

    I gave each class a different longint value. From what I've read this seems to be the thing to do, but I'm still uncertain.
    yes, this is the solution. you say "it made no difference". it made some difference. what error did you get after you did this?
  • 5. Re: Serialization error - apparently unusual
    942608 Newbie
    Currently Being Moderated
    Hello,

    The error is exactly the same with and without explicit serialVersionUIDs.

    Sorry, I mis-spoke again. The error remained unchanged in every aspect of its overt behavior, after adding the UIDs. The same changes in the code can cause de-serialization to fail. Further, the stack trace is character-for-character exactly the same regardless of the presence or absence of the explicit UIDs.

    Go figure.

    Thanks again.

    c lanz
  • 6. Re: Serialization error - apparently unusual
    jtahlborn Expert
    Currently Being Moderated
    clanz wrote:
    The error is exactly the same with and without explicit serialVersionUIDs.

    Sorry, I mis-spoke again. The error remained unchanged in every aspect of its overt behavior, after adding the UIDs. The same changes in the code can cause de-serialization to fail. Further, the stack trace is character-for-character exactly the same regardless of the presence or absence of the explicit UIDs.
    i doubt that. if you created the serialVersionUIDs correctly, then the new ids should be mentioned in the error message. if not, then you didn't create them correctly. if so, then the problem is that you have existing serialized data without the explicit uids, in which case (assuming the old class data is compatible), then you should make the explicit serialVersionUIDs the same as the old, implicit ones.

    and no, once you have added the explicit serialVersionUIDs, the addition/removal of static members will not affect anything. if it does, then you still have not done the explicit ids correctly.
  • 7. Re: Serialization error - apparently unusual
    EJP Guru
    Currently Being Moderated
    Go figure.
    Easy. You ran the old code.
  • 8. Re: Serialization error - apparently unusual
    942608 Newbie
    Currently Being Moderated
    OK, good thanks to you both, I've made certain that there is no old code to run or any old files to gum up the works. Neither had any obvious impact.

    I checked again, and the traces were in fact identical. However, acting on your advice, I made a pass through the code for typos and to to make sure I hadn't given the same UID to 2 classes, and I noticed I had a superfluous "implements Serializable" in a class that appears in a field of the class I actually write out to disk. I removed that, and some debugging code, and then ran the whole test series again, and, as you predicted, there is now one line difference between the traces (that is, between the error trace with and then without explicit UIDs.) Here is the beginning of the trace made with explicit UIDs, and the complete trace that happens if there are no explicit UIDs (I hope this helps):

    TRACE AFTER FAIL WITH EXPLICIT UIDs

    java.io.InvalidClassException: wdaxwns.Primitives; local class incompatible: stream classdesc serialVersionUID = 3479924330845076229, local class serialVersionUID = 190094503397420067

         at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579) <-- DIFFERENT
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
    etc. all exactly as below

    TRACE AFTER FAIL WITHOUT EXPLICIT UIDs

    java.io.InvalidClassException: wdaxwns.Primitives; local class incompatible: stream classdesc serialVersionUID = 3479924330845076229, local class serialVersionUID = 190094503397420067

         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
         at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
         at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
         at wdaxwns.Primitives.massLoadAxis(Primitives.java:784)
         at wdaxwns.WdAx.firstInit(WdAx.java:218)
         at wdaxwns.WdAx.main(WdAx.java:91)
    java.io.InvalidClassException: wdaxwns.Primitives; local class incompatible: stream classdesc serialVersionUID = 3479924330845076229, local class serialVersionUID = 190094503397420067
         at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:579)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
         at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1600)
         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1513)
         at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
         at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
         at wdaxwns.Primitives.massLoadWord(Primitives.java:824)
         at wdaxwns.WdAx.firstInit(WdAx.java:219)
         at wdaxwns.WdAx.main(WdAx.java:91)


    Also, as you noted, the explicit UIDs that I set don't show up in these traces, and I think you meant to imply that I am setting them wrong. Now, JavaPractices suggests:

    --------------------------
    The serialVersionUID is a universal version identifier for a Serializable class. Deserialization uses this number to ensure that a loaded class corresponds exactly to a serialized object. If no match is found, then an InvalidClassException is thrown.

    Guidelines for serialVersionUID :

    always include it as a field, for example: "private static final long serialVersionUID = 7526472295622776147L; " include this field even in the first version of the class, as a reminder of its importance
    do not change the value of this field in future versions, unless you are knowingly making changes to the class which will render it incompatible with old serialized objects
    new versions of Serializable classes may or may not be able to read old serialized objects; it depends upon the nature of the change; provide a pointer to Sun's guidelines for what constitutes a compatible change, as a convenience to future maintainers
    ------------------------------

    As far as I can tell, I am conforming to these guidelines.

    Looking at Sun's guidelines, section 5.6.1 lists incompatible changes, and I am certain that I make no such changes between runs that work and those that fail. Admittedly, this list appears in documentation covering evolving classes, and the list name implies that it is considering only changes made in the serialized class, not elsewhere in the program. I have not found an effective search for discussions or docs on such changes, but I'll continue that effort presently.

    Thanks again for your time.

    c lanz
  • 9. Re: Serialization error - apparently unusual
    jtahlborn Expert
    Currently Being Moderated
    the fact that your explicit UIDs are not showing up in the exception trace means that you are doing something wrong, or not running the code that you think you are running. (i assume "wdaxwns.Primitives" is one of the classes which you control).
  • 10. Re: Serialization error - apparently unusual
    EJP Guru
    Currently Being Moderated
    local class serialVersionUID = 190094503397420067
    If the source code of the local class has a different value for the private static long serialVersionUID than what appears in the error message, you aren't using the corresponding .class file at execution time, or else it isn't static and long.

    There is no other possibility.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points