chris bailey

java objectinputstream invalid type code: ac, why...

While using ObjectInputStream and ObjectOutputStream together for a class project I continually ran into java objectinputstream invalid type code: ac which was becoming endlessly annoying. Initially, I was attempting to use try-with-resources blocks to limit my need for finally catches, but this proved to be the main culprit in my issue.

public static void main(String[] args) {
  try (FileOutputStream fo = new FileOutputStream(db)) {
    try (ObjectOutputStream oo = new ObjectOutputStream(fo)) {
      // do stuff
    }
  }
}

public static void StuffDoer() {
  try (FileInputStream fi = new FileInputStream(db)) {
    try (ObjectInputStream oi = new ObjectInputStream(fi)) {
      // read stuff
    }
  }
}

From what I've been able to gather this has to with ObjectOutputStream writing the headers and sharing between the two, but only while it has not been closed, once closed and we attempt to open a second/new stream it's no longer able to handle the binary data that has been written.

Since I'm still a 🐶 in this Java stuff, research was needed and StackOverflow seems to have provided it. this answer was what I found to work best for my use cases. It creates a class extending ObjectOutputStream that basically avoids writing the headers each time as far as I can tell, it's still kind of magic to me.

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

public class AppendableObjectOutputStream extends ObjectOutputStream {

    private boolean append;
    private boolean initialized;
    private DataOutputStream stdout;

    protected AppendableObjectOutputStream(boolean append) throws IOException, SecurityException {
        super();
        this.append = append;
        this.initialized = true;
    }

    public AppendableObjectOutputStream(OutputStream out, boolean append) throws IOException {
        super(out);
        this.append = append;
        this.initialized = true;
        this.dout = new DataOutputStream(out);
        this.writeStreamHeader();
    }

    @Override
    protected void writeStreamHeader() throws IOException {
        if (!this.initialized || this.append) return;
        if (stdout != null) {
            stdout.writeShort(STREAM_MAGIC);
            stdout.writeShort(STREAM_VERSION);
        }
    }

}

Usage of the class will be nearly same as just outright using ObjectOutputStream

File file = new File('some.dat');
boolean append = file.exists();
try ( FileOutputStream fo = new FileOutputStream(file, append);
  AppendableObjectOutputStream ao = new AppendableObjectOutputStream(fo, append);) {
    oo.writeObject(...);
  } catch(...) {
    // catch some stuff
  }