State of Serialization (original) (raw)

Peter Firmstone peter.firmstone at zeus.net.au
Sun Jul 20 10:57:20 UTC 2014


David,

I've gone over the list archives and read your earlier post about serializable constructors and agree with your post.

The class SerialFields below, represents the serial form of a Serializable object, the stream protocol would remain unchanged.

SerialFields would be the equivalent of an existing Serializable object that declares

private static final ObjectStreamField[] serialPersistentFields

and uses PutField in it's writeObject method and GetField in its readObject method.

Regards,

Peter.

State of Java Serialization

Introduction

The Java Serialization framework enables object state to be frozen, stored to disk or transferred over a network and unfrozen again into objects. While Java's Serialization capabilities are arguably more sophisticated than most at reconstructing complex object relationships, the “magic” nothing to do, marker interface, Serializable is problematic. Due to the complexity of serialising state from an object with Serializable superclasses in inheritance hierarchies, private methods were chosen, allowing objects to write and read objects to and from streams. Each class in an Object's inheritance heirarchy that implements or inherits Serializable must be able to write out and read in serialized state, private methods cannot be overridden or called by subclasses, nor is their implementation enforced by the Java language syntax, hence Serializable is a marker interface only.

Background

Serialization was introduced in Java 1.1. The marker interface Serializable is problematic since implementation of its methods are optional. Developers can make objects serializable by simply declaring implements Serializable and providing a default zero argument constructor.

Since private methods are only be called by the ObjectOutputStream / ObjectInputStream, during de-serialisation, subclass are not responsible for calling these methods, hence subclass ProtectionDomain's are not present in the Thread's AccessControlContext and as such are missing from security checks, this is why it's currently essential for classes to ensure that de-serialisation isn't performed in a privileged context.

To improve security, it would be preferable to use a deserialization constructor, required to be called by subclasses in the class hierarchies, placing their ProtectionDomains in the stack context, avoiding a number of security issues. Another benefit is the ability to use final fields, while checking invariants during construction.

import java.io.Serializable;

/**

/**

}

import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;

/**

public static SerialFields create() throws SecurityException { // Perform security check. return new SerialFields(); }

private final Map<FieldKey,Object> fields; private final List order;

/**

/**

/** *

private static class FieldKey { private final Class caller; private final String fieldName; private final int hash;

FieldKey(Class caller, String fieldName){ this.caller = caller; this.fieldName = fieldName; int hash = 3; hash = 79 * hash + (this.caller != null ? this.caller.hashCode() : 0); hash = 79 * hash + (this.fieldName != null ? this.fieldName.hashCode() : 0); this.hash = hash; }

@Override public int hashCode() { return hash; }

@Override public boolean equals(Object o){ if (!(o instanceof FieldKey)) return false; FieldKey that = (FieldKey) o; if (!caller.equals(that.caller)) return false; return fieldName.equals(that.fieldName); } } }



More information about the core-libs-dev mailing list