3
public class ExternalizableClass implements Externalizable
{
  public static ExternalizableClass CACHE = new ExternalizableClass(-1);

  int id;

  public ExternalizableClass()
  {
    id = (int)(Math.random() * 1000);
  }

  public ExternalizableClass(int i)
  {
    id = i;
  }


  @Override
  public void writeExternal(ObjectOutput out) throws IOException
  {
    out.writeInt(id);
  }

  @Override
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
  {
    //id = in.readInt();
    id = in.readInt();
  }


  public Object writeReplace() throws ObjectStreamException
  {
    return new Write(0);
  }

  private class Write extends ExternalizableClass
  {
    int value;

    public Write()
    {
    }

    public Write(int i)
    {
      value = i;
    }

    public Object readResolve() throws ObjectStreamException
    {
      return ExternalizableClass.CACHE;
    }


  }

  @Override
  public String toString()
  {
    return "id: " + id;
  }

  public static void main(String[] argv)
  {
    try
    {
      ExternalizableClass ex = ExternalizableClass.CACHE;

      System.out.println(ex);

      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp.txt"));
      oos.writeObject(ex);

      oos.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

    ExternalizableClass ex;
    try
    {
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp.txt"));
      ex = (ExternalizableClass) ois.readObject();

      System.out.println(ex);

      ois.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }
}

Both ExternalizableClass and ExternalizableClass.Write class have default (non-arg) constructors. But when deserializing it, Java complains:

java.io.InvalidClassException: SeralizableTest.ExternalizableClass$Write; no valid constructor
    at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
    at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1772)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at SeralizableTest.ExternalizableClass.main(ExternalizableClass.java:124)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Can anyone explain what the problems are?

OneZero
  • 11,556
  • 15
  • 55
  • 92

1 Answers1

6

I suspect the problem is that it's an inner class... so it doesn't actually have a parameterless constructor. Instead, it has two constructors, one of which takes a reference to an instance of the enclosing class, and one of which takes a reference to an instance of the enclosing class and an int.

If you make it just a nested class by adding the static modifier to the class declaration (for Write) then I suspect it'll be fine, because then it won't have the implicit extra parameter on each constructor.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Where do you get this info? Did you read the entire specification or something? Or do you just stumble across it within time? Or do you have some special "skeet only" search engine? How do you do your magic? This is a serious question btw; I really want to know if you just know this stuff already, or if you have some special way of searching for things? – Vince Dec 27 '14 at 20:59
  • @VinceEmigh Well, he *is* Jon Skeet, but someone really familiar with Java (such as myself) can identify the problem just by looking at the declaration of `Write`. – chrylis -cautiouslyoptimistic- Dec 27 '14 at 21:02
  • @Jon Skeet That solved my problem. Thanks! Can you explain a bit about the `implicit extra parameter` you mentioned though? – OneZero Dec 27 '14 at 21:15
  • 2
    @OneZero When creating an inner-class, the inner class must have a reference to an instance of the outter class. To achieve this (apparently), inner classes are given implicit constructor parameters so the outter instance can be passed to the inner – Vince Dec 27 '14 at 21:30
  • @VinceEmigh: A mixture of experience telling me what inner classes do, along with a bit of logical thinking to see how it caused this error. Nothing terribly exciting, I'm afraid... (No searching required in this case.) – Jon Skeet Dec 27 '14 at 21:38