Hello. I'm trying to serialize a class that implements Serializable and a Runnable. My class has a transient Thread object as a field that is created and started after the restoration of my class(object).

This is proven possibile by a tutorial from Oracle, here. But i fail to compile my program which is very similar to the one in the tutorial(i think).

So in the following i attach my source code and the exception's trace in hope that someone can help me out.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ppc2;

import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {

    Main(){

        SerializedThread [] threads = new SerializedThread[7];
        for(int i =1 ;i<8;i++){
            if(i==1)
                threads[i] = new SerializedThread(new String[]{"f2","f3","f4"});
            if(i==2)
                threads[i] = new SerializedThread(new String[]{"f5"});
            if(i==3)
                threads[i] = new SerializedThread(new String[]{"f6"});
            if(i==4)
                threads[i] = new SerializedThread(new String[]{"f7"});
        }
        for(int i =0;i<7;i++){
            writeMyObjectToFile(threads[i],"f"+(i+1));
        }
        readMyObjectFromFile("f1");
    }

    private void writeMyObjectToFile(SerializedThread runner, String fileName){
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try{
            fos = new FileOutputStream(fileName);
            oos = new ObjectOutputStream(fos);
            oos.writeObject(runner);
            oos.close();
        }catch(IOException e){
            e.printStackTrace();
        }

    }
    private SerializedThread readMyObjectFromFile(String fileName){
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        SerializedThread runner = null;
        try{
            fis = new FileInputStream(fileName);
            ois = new ObjectInputStream(fis);
            runner = (SerializedThread)ois.readObject();
            ois.close();
        }catch(IOException e){
            e.printStackTrace();
        }catch(ClassNotFoundException ex){
            ex.printStackTrace();
        }
        return runner;
    }

    public static void main(String[] args) {
        new Main();

    }

    class SerializedThread implements Serializable, Runnable {

        transient private SerializedThread[] children = null;
        transient public Thread self = null;
        private String[] childrenFileNames = null;

        SerializedThread(String[] childrenFileNames) {
            setNames(childrenFileNames);
        }

        public void setNames(String[] childrenFileNames) {
            this.childrenFileNames = childrenFileNames;
        }

        @Override
        public void run() {
            restoreGivenChildren();//They will auto start, because of the "start" comand in the readObject function.
        }

        private void restoreGivenChildren() {
            if (childrenFileNames != null) {
                children = new SerializedThread[childrenFileNames.length];
                for (int i = 0; i < childrenFileNames.length; i++) {
                    children[i] = (SerializedThread) readMyObjectFromFile(childrenFileNames[i]);
                    //children[i].self=new Thread(this);
                    children[i].self.start();
                }

            }
        }

//        private void writeObject(ObjectOutputStream out) throws IOException {
//            out.defaultWriteObject();
//        }
//
//        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//            // our "pseudo-constructor"
//            in.defaultReadObject();
//            // now we are a "live" object again, so let's run rebuild and start
//            self = new Thread(this);
//            self.start();
//        }
    }
}

The error>>>

run:
java.io.NotSerializableException: ppc2.Main
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
        at ppc2.Main.writeMyObjectToFile(Main.java:42)
        at ppc2.Main.<init>(Main.java:31)
        at ppc2.Main.main(Main.java:67)
java.io.NotSerializableException: ppc2.Main
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
        at ppc2.Main.writeMyObjectToFile(Main.java:42)
        at ppc2.Main.<init>(Main.java:31)
        at ppc2.Main.main(Main.java:67)
java.io.NotSerializableException: ppc2.Main
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
        at ppc2.Main.writeMyObjectToFile(Main.java:42)
        at ppc2.Main.<init>(Main.java:31)
        at ppc2.Main.main(Main.java:67)
java.io.NotSerializableException: ppc2.Main
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
        at ppc2.Main.writeMyObjectToFile(Main.java:42)
        at ppc2.Main.<init>(Main.java:31)
        at ppc2.Main.main(Main.java:67)
BUILD SUCCESSFUL (total time: 0 seconds)

Dani AI

Generated

nailed the root cause: SerializedThread is a non-static inner class, so the compiler adds a hidden reference to the enclosing Main. Default serialization walks all reachable fields; that hidden outer reference pulls in Main, which is not Serializable, so you get NotSerializableException. The Java serialization spec explicitly discourages serializing non-static inner classes for exactly this reason. Moving the class top-level or making it a static nested class is the right fix. See the note under the Serializable interface in the spec. Oracle serialization spec. (docs.oracle.com)

Also, to ’s point: you do not need a no-arg constructor on the serializable class itself; during deserialization Java invokes the no-arg constructor of the first non-serializable superclass. Spec: deserialization rules. (docs.oracle.com)

Two practical tips for :

One safe pattern is to rebuild transient state in readObject, but delay starting threads until an explicit call:

static class SerializedTask implements Serializable, Runnable {
    private static final long serialVersionUID = 1L;
    transient Thread self;
    String[] childFiles;

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();      // restore non-transient state
        self = new Thread(this);     // reinit, but do not start here
    }

    void startAfterRestore(Function<String, SerializedTask> loader) {
        if (childFiles != null) for (String f : childFiles)
            new Thread(loader.apply(f)).start();
        self.start();
    }

    public void run() { /* work */ }
}

If you scale this up, prefer an ExecutorService over creating raw threads. Executors Javadoc. (docs.oracle.com)

Recommended Answers

All 4 Replies

Don't have time to cehck this now, but don't you need a default constructor for a Serialisable class to be restored?

I don't see why, but i added one anyway... and corrected some logic bugs, but the error is the same.
This is my source code now:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ppc2;

import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {

    Main(){

        SerializedThread [] threads = new SerializedThread[7];
        for(int i =1; i < 8; i++) {
            switch (i) {
                case 1:
                    threads[i - 1] = new SerializedThread(new String[]{"f2", "f3", "f4"});
                    break;
                case 2:
                    threads[i - 1] = new SerializedThread(new String[]{"f5"});
                    break;
                case 3:
                    threads[i - 1] = new SerializedThread(new String[]{"f6"});
                    break;
                case 4:
                    threads[i - 1] = new SerializedThread(new String[]{"f7"});
                    break;
                default:
                    threads[i - 1] = new SerializedThread(null);
            }
        }
        for(int i =0;i<7;i++){
            writeMyObjectToFile(threads[i],"f"+(i+1));
        }
        readMyObjectFromFile("f1");
    }

    private void writeMyObjectToFile(SerializedThread runner, String fileName){
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try{
            fos = new FileOutputStream(fileName);
            oos = new ObjectOutputStream(fos);
            oos.writeObject(runner);
            oos.close();
        }catch(IOException e){
            e.printStackTrace();
        }

    }
    private SerializedThread readMyObjectFromFile(String fileName){
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        SerializedThread runner = null;
        try{
            fis = new FileInputStream(fileName);
            ois = new ObjectInputStream(fis);
            runner = (SerializedThread)ois.readObject();
            ois.close();
        }catch(IOException e){
            e.printStackTrace();
        }catch(ClassNotFoundException ex){
            ex.printStackTrace();
        }
        return runner;
    }

    public static void main(String[] args) {
        new Main();

    }

    class SerializedThread implements Serializable, Runnable {

        transient private SerializedThread[] children = null;
        transient public Thread self = null;
        private String[] childrenFileNames = null;

        SerializedThread() {}
        SerializedThread(String[] childrenFileNames) {
            setNames(childrenFileNames);
        }

        public void setNames(String[] childrenFileNames) {
            this.childrenFileNames = childrenFileNames;
        }

        @Override
        public void run() {
            restoreGivenChildren();//They will auto start, because of the "start" comand in the readObject function.
        }

        private void restoreGivenChildren() {
            if (childrenFileNames != null) {
                children = new SerializedThread[childrenFileNames.length];
                for (int i = 0; i < childrenFileNames.length; i++) {
                    children[i] = (SerializedThread) readMyObjectFromFile(childrenFileNames[i]);
                    children[i].self=new Thread(this);
                    children[i].self.start();
                }

            }
        }

//        private void writeObject(ObjectOutputStream out) throws IOException {
//            out.defaultWriteObject();
//        }
//
//        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//            // our "pseudo-constructor"
//            in.defaultReadObject();
//            // now we are a "live" object again, so let's run rebuild and start
//            self = new Thread(this);
//            self.start();
//        }
    }
}

Me errors>>>

java.io.NotSerializableException: ppc2.Main
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
        at ppc2.Main.writeMyObjectToFile(Main.java:50)
        at ppc2.Main.<init>(Main.java:39)
        at ppc2.Main.main(Main.java:75)

SerializedThread is an inner class i.e. a class which depends on some outer parent class i.e. there is an association between your class Main and SerializedThread. When you try to serialize SerializedThread, it also tries to serialize Main class (which doesn't implement Serializable) hence the error.

A couple of solutions: make the main class implement Serializable (not recommended) or move the SerializedThread out of Main (recommended).

commented: solved +3

Thank you. I separated the classes and the serialization works.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.