Hi, Peter Levart and I have been working on an API to support setting of final fields during custom deserialization. Dealing with final fields during deserialization is a pain point only partially addressed in JSR 133 ( in Java 5 ). What we are proposing is a simple API solution to resolve this.
Current limitations ( primary motivation for the new API ): * defaultReadObject can set final fields, but it is somewhat limiting. The fields must have a value in the deserialized stream. This is not flexible when evolving a classes representation, or when dealing with transient final fields. * Setting final fields in readObject using reflection requires java.lang.reflect.ReflectPermission("suppressAccessChecks"). Granting this permission, when only required to set final fields during custom deserialization, is dangerous. Information (possibly confidential) and methods normally unavailable may be accessible to malicious code. * It is not possible to grant 'suppressAccessChecks' for particular classes or objects, or restrict the ability to set final fields through reflection for the period of the readObject callback, and just for the object being reconstructed. * Using reflection to set final fields can have a performance cost, as the reflective implementation may issue a barrier for each field set. Outline of the new API: * New interface ObjectInputStream.FieldAccess with overloaded set(name, value) methods. Similar in some respects to Get/PutField, but with j.l.r.Field semantics. * The FieldAccess instance is retrieved from ObjectInputStream.fields(), which can only be called during a readObject callback. Similar to readFields() (returns GetField). * FieldAccess, once retrieved, ensures that all final fields are set, and set only once. * No behaviour changes to existing code. Unless fields() is called existing code is unaffected. * Can be used with either GetFields, or defaultReadObject. Specification: http://cr.openjdk.java.net/~chegar/8071472/00/specdiff/ Example: class Stamp implements Serializable { private transient final long millis; Stamp() { millis = System.currentTimeMillis(); } public long stamp() { return millis; } private void readObject(java.io.ObjectInputStream in) throws Exception { in.fields().set("millis", System.currentTimeMillis()); } } We have a fully working implementation, tests, etc, in the sandbox: hg clone http://hg.openjdk.java.net/jdk9/sandbox sandbox cd sandbox sh get_source.sh sh common/bin/hgforest.sh update -r serial-exp-branch Webrev for convenience: http://cr.openjdk.java.net/~chegar/8071472/00/webrev/ Feedback welcome. -Chris.