2

I am reading Thinking in Java 4th Edition. There described a strange workaround for serialization of transient fields:

import java.io.*;

public class SerializationTest implements Serializable {
    private String firstData;
    //transient field, shouldn't be serialized.
    transient private String secondData;

    public SerializationTest(String firstData, String test2) {
        this.firstData = firstData;
        this.secondData = test2;
    }

    /**
     * Private method, same signature as in Serializable interface
     *
     * @param stream
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream stream) throws IOException {
        stream.defaultWriteObject();
        stream.writeObject(secondData);
    }

    /**
     * Private method, same signature as in Serializable interface
     *
     * @param stream
     * @throws IOException
     */
    private void readObject(ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        secondData = (String) stream.readObject();

    }

    @Override
    public String toString() {
        return "SerializationTest{" +
                "firstData='" + firstData + '\'' +
                ", secondData='" + secondData + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try {
            fos = new FileOutputStream("object.out");
            oos = new ObjectOutputStream(fos);
            SerializationTest sTest = new SerializationTest("First Data", "Second data");
            oos.writeObject(sTest);
        } finally {
            oos.close();
            fos.close();
        }
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fis = new FileInputStream("object.out");
            ois = new ObjectInputStream(fis);
            SerializationTest sTest = (SerializationTest) ois.readObject();
            System.out.println(sTest);
        } finally {
            ois.close();
            fis.close();
        }
        //Output:
        //SerializationTest{firstData='First Data', secondData='Second data'}
    }
}

As you can see, there are implemented private methods writeObject and readObject.

The questions are:

For what ObjectOutputStream and ObjectInputStream are using Reflection for accessing private methods ?

How many back doors like this are included in the Java ?

StKiller
  • 7,631
  • 10
  • 43
  • 56
  • 3
    Not a back door but http://stackoverflow.com/questions/15496/hidden-features-of-java – OscarRyz Apr 15 '11 at 21:11
  • Btw, your resource handling isn't done correctly. The standard form is: `Resource resource = acquire(); try { use(resource); } finally { resource.release(); }`. You should do this individually for each resource. In Java SE 6, you can write `try (Resource resource = acquire()) { use(resource); }` in most cases. There's no need to close your object streams, other than to flush the `ObjectOutputStream` in the happy case only (that is to say in the body of the `try`; flusihing in the `finally` will also do it in the error case, which isn't really what you want). – Tom Hawtin - tackline Apr 15 '11 at 21:30
  • @Tom: The `try(...){` syntax is already in Java SE 6? This is new to me, I thought it would be only 7. – Paŭlo Ebermann Apr 15 '11 at 23:34
  • @Paŭlo Ebermann Typo. Should read "in Java SE 7". (And you shouldn't be able to use `-target 1.6 -source 1.7`. In addition to the rule that the target needs to be at least as current as the source, it requires additional library support. Perhaps Retroweaver or similar will hack something up.) – Tom Hawtin - tackline Apr 16 '11 at 18:48

3 Answers3

7

Backdoor? It's always been in the spec. It is the only way to implement non-default serialization of an object.

Non-default serialization puts you in the serialization driver's seat. You can write whatever to the output stream and as long as you can read it back and construct your object on the other end of the stream, you'll be ok.

The fact that this person decided to serialize transient fields is just not the issue, the point is that you can do whatever you want if you are implementing your own serialization scheme.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
3

Erm, it isn't a "backdoor" ... you implemented a custom serialization that output the transient fields to the output stream after calling the default serialization which ignored them.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
1

The Serializable interface is marker interface. So its like a tag to explain the java compiler. There are other marker interfaces like Clonable, etc. See here for more. However now a days @annotations are used more.

kinshuk4
  • 3,241
  • 3
  • 33
  • 41