28

The following code:

public class TestInnerClass {

    public static void main(String[] args) throws IOException {
        new TestInnerClass().serializeInnerClass();
    }

    private void serializeInnerClass() throws IOException {
        File file = new File("test");
        InnerClass inner = new InnerClass();
        new ObjectOutputStream(new FileOutputStream(file)).writeObject(inner);
    }

    private class InnerClass implements Serializable {

        private static final long serialVersionUID = 1L;

    }

}

throws the following exception:

Exception in thread "main" java.io.NotSerializableException: TestInnerClass

I guess the inner class has a TestInnerClass.this field that allows it private access to TestInnerClass's fields and methods. Declaring the inner class static solves it, but what if InnerClass needs this access? Is there a way to serialize a non-static inner class without the enclosing class, e.g. by making the reference to the outer class transient?

edit: for example, access to the outer class could be needed only before serialization. OK, the compiler cannot know that, but I thought that's why the transient keyword exists.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
tb189
  • 1,942
  • 3
  • 22
  • 37

3 Answers3

34

what if InnerClass needs this access?

Then it needs the outer class instance, and it must be serialized along with the inner class.

Is there a way to serialize a non-static inner class without the enclosing class, e.g. by making the reference to the outer class transient?

No. What would happen when you deserialize such a class and then try to call an instance method of the outer class? A NullPointerException?

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • 1
    In my situation, the inner class needs access before it is actually serialized (not after deserialization). It is afterwards only used as a superclass who does not know of the outer class. – tb189 Aug 22 '11 at 08:58
  • 5
    @tb189: You can always break the non-static dependency by adding a field `transient TestInnerClass parentClass` to `InnerClass` and take care of it when deserializing. – dma_k Aug 22 '11 at 09:02
  • That would indeed be a way to deal with it, and resembles a transient reference to the `TestInnerClass.this`. – tb189 Aug 23 '11 at 07:08
  • @dma_k `outerClass`, you mean. outer != parent. Although you're right that it is the solution. – Boann Jul 12 '14 at 19:13
  • @Boann: In the example above `InnerClass` is inner class, `TestInnerClass` is outer class. If given inner class would be nested class, then the exception wouldn't be raised, as nested class has no implicit reference to it's container class. See [this post](http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class) concerning the terminology. – dma_k Aug 26 '14 at 09:29
  • @dma_k Hmm? I know. Why are you telling me? – Boann Aug 26 '14 at 11:14
  • Ah, sorry, I thought that you asked for clarification. Yes, you're right, I meant `TestInnerClass outerClass`, but I cannot edit my comment. – dma_k Aug 27 '14 at 16:05
2

InnerClass cannot be serialised because to instantiate it (as required during deserialization) you need a reference to an instance of the outer class

Instances of inner classes cannot exist without an instance of the outer class.

i.e

OuterClass o = new OuterClass();
OuterClass.InnerClass o_i = o.new InnerClass();

If you use static inner class, it will be possible to serialise the static inner class. The instances of static inner classes can be created standalone.

i.e

OuterClass o = new OuterClass();
OuterClass.InnerClass i = new OuterClass.InnerClass();
Adonis
  • 4,670
  • 3
  • 37
  • 57
Mathew
  • 21
  • 2
  • Perhaps making a Github gist or a full reproducible example would be nice, don't you think? – Adonis Jun 29 '17 at 07:42
2

how about make TestInnerClass serializable?

public class TestInnerClass implements Serializable { }
hellojinjie
  • 1,868
  • 3
  • 17
  • 23
  • 2
    That's possible, but not always desired, since that adds a lot of data to the serialized class. – tb189 Aug 22 '11 at 08:55
  • @EJP: there are always solutions that could be more preferable (separating the parts of the inner class that need access and then forward it to a static serializable class, using a transient field TestInnerClass, maintainging another serializable object in the inner class). It would also imply declaring all fields in the outer class transient, which seems like a design flaw. It's not because the present situation doesn't work that the first alternative/hack should immediately be used. – tb189 Aug 23 '11 at 07:15