4

I have been searching web to find the answers of some of the queries related to enum class in java.

My query is why default De-serialization has been prevented in enum class. I can see that the enum class implements Serializable interface but it also have 2 methods as below --

 private void readObject(ObjectInputStream in) throws IOException,
    ClassNotFoundException {
    throw new InvalidObjectException("can't deserialize enum");
}

private void readObjectNoData() throws ObjectStreamException {
    throw new InvalidObjectException("can't deserialize enum");
}

I am more confused after seeing this class. Any help will be appreciated. Thanks in advance.

I am more confused since ENUM implements serializable interface itself and have above methods too that throws "throw new InvalidObjectException("can't deserialize enum");" Exception. so i am not getting clear understanding of what above two methods are for ?

Also comments on above two methods says "prevent default deserialization" what does it mean ?

rraghuva
  • 131
  • 1
  • 10

2 Answers2

4

Enumeration values are serializable -- and that's all that is claimed by implementing the Serializable interface.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Dummy {

    public enum Color {
        RED, GREEN, BLUE
    }

    public static void main(String[] args) throws Exception {

        System.out.println(deserialize(serialize(Color.GREEN), Color.class));
    }

    private static <T> T deserialize(byte[] data, Class<T> cls) throws IOException, ClassNotFoundException {

        try (final ByteArrayInputStream stream = new ByteArrayInputStream(data);
             final ObjectInputStream reader = new ObjectInputStream(stream)) {

            return cls.cast(reader.readObject());
        }
    }

    private static byte[] serialize(Serializable obj) throws IOException {

        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        try {

            try (final ObjectOutputStream writer = new ObjectOutputStream(stream)) {

                writer.writeObject(obj);
            }

        } finally {

            stream.close();
        }

        return stream.toByteArray();
    }
}

However, due to the special nature of enumeration constants, the run-time cannot use the default serialization mechanism, as that would allow the construction of multiple values of a given constant, violating the guarantee, that enumeration constants are singletons.

For this reason, the run-time uses a "non-default" mechanism to serialize/deserialize enumeration constants, which ensures the singleton property. Disarming the default mechanism by overriding readObject is simply a security measure, which makes sure, that you cannot trick the VM into creating new constants by having it deserialize a maliciously hacked byte stream.

TL;DR Enumeration constants are perfectly (de)serializable as claimed by having the base class Enum implement the Serializable interface. However, internally, the VM/run-time handles the serialization specially, and disables the default mechanism for these kinds of objects.

Dirk
  • 30,623
  • 8
  • 82
  • 102
2

Simple because in Java enum is singleton in JVM, and deserialize() would create another instance thus break the singleton contract.

Alex Suo
  • 2,977
  • 1
  • 14
  • 22
  • It means we can serialize Enum but cant deserialize it ? – rraghuva Jan 04 '16 at 10:52
  • Since `deserialize()` is blocked you cannot use the default way to transfer `enum` objects i.e. serialize `enum` objects, hoping they could be deserialized in another JVM correctly. A common way is to use the `cardinal()` value. – Alex Suo Jan 04 '16 at 10:54