JDK-6252102 : unpredictable behavior of "transient" keyword during serialization and deserialization
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io:serialization
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2005-04-07
  • Updated: 2013-05-01
Related Reports
Relates :  
J2SE Version (please include all output from java -version flag):
  java version "1.6.0-ea"
  Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-ea-b28)
  Java HotSpot(TM) Client VM (build 1.6.0-ea-b28, mixed mode)

Does this problem occur on J2SE 1.4.x or 5.0.x ?  Yes / No (pick one)

Bug Description:
  strange and also unpredictable behavior of Java concerning 
  the semantics of the "transient" keyword during serialization 
  and deserialization.

Steps to Reproduce (be specific):
  This example Main.java demonstrates the problem of the "transient"
  keyword during serialization and deserialization.

###@###.### 2005-04-07 17:05:23 GMT

EVALUATION I reversed my inclination to use this particular CR to track the problem of initializing final instance fields upon deserialization-- upon later reflection, doing so is a bit of a stretch for this CR, and a newer RFE was filed specifically for that problem: see 6379948. That leaves this CR being about the confusion regarding how "transient", "final", and constant initializers affect serialization behavior, and whether there should be some sort of compiler warning to help avoid pitfalls in this area. Offhand, I'm not entirely what such a warning would be (it couldn't just be on serializable classes' transient fields with instance initializers, because the transient modifier only affects a serializable class's default serializable fields when the class does not declare a "serialPersistentFields" field). It seems that a combination of a solution for 6379948, along with good documentation for how to use it, would be the best outcome there. There is not a behavioral bug here, because the transient modifier is having the effect that it is specified to have for serialization (a transient field is not one the classes default serializable fields), and the final modifier (with and without a constant intializer) is having the effect specified by the JLS. Perhaps the aspect that many users find most confusing is the fact that instance field initializers for non-serializable (transient) instance fields are not executed upon deserialization, just like how constructors aren't-- perhaps this fact should be emphasized more explicitly and obviously in the appropriate documentation, so that the reported behavior is less likely to seem "unpredictable".

WORK AROUND Also there is another interesting thing related with serializing objects with transient fields. For our base class we may define parent which does not implement Serializable interface and contains "transient" and/or "final transient" fields. We may initialize these fields in points of its declaration or in public constructor. In that case, according of specification of serialization after de-serialization first public constructor of non-serializable parent class is invoking for obtaining and construction the instance of our base class. In that case, all defined final transient constants in parent object will be initialized in our base object as inherited fields. This situation is represented in attached source code (see file source2.tar). For obtaining that case, compile all source and run class NewMain.

EVALUATION This CR is essentially about the problem of initializing a serializable class's final instance fields upon deserialization-- for such fields not among the set of a class's official serializable fields, when default serialization is used (like when the class's readObject method invokes ObjectInputStream,defaultReadObject), or for all such fields when the class's readObject method uses the ObjectInputStream.readFields/GetField API to read serializable field values programmatically from the stream. No language-level constructor gets invoked for a serializable class upon deserialization (and this includes instance field initializers too, alas), so instance fields not set by default serialization need to be set by the class's custom readObject method, which (if present) does get invoked upon deserialization instead. A readObject method, however, does not have the ability to initialize final fields like a real constructor does; hence the problem. The "transient" keyword only comes into play here because, when a serializable class does not declare its serializable fields explicitly with "serialPersistentFields", the "transient" keyword is what designates an instance field as not being one of the class's serializable fields; in that case, a transient field never gets set by ObjectInputStream upon deserialization. The effect of the "transient" keyword demonstrated by the submitted test case is exactly as expected-- in the submitted code as is (with the readObject method commented out), most of the transient fields appear to end up with the value zero upon deserialization because no constructor or readObject method initializes them. The "b" field, however, appears to have an initialized value because its initializer is actually a compile-time constant expression, so the Java compiler inlines its value. The same effect would be demonstrated by, instead of using the "transient" keyword (or independent of its use), using a "serialPersistentFields" declaration to explicitly designate "a", "c", "e", and "g" as the class's serializable fields. With the readObject method uncommented, transient fields "d" and "h" can be properly initialized, but "f" cannot because it is final. The problem of initializing a serializable class's final instance fields upon deserialization (other than through default serialization) is well known, but I don't think that there is a CR open to track the issue, so it seem that this CR could be used for that purpose. I'm not sure what is the likelihood of a solution in the forseeable future, though. ###@###.### has interest in this problem and has proposed some solutions to think about. Regarding a Java compiler warning, in lieu of a real solution to the problem, it may be worth considering such a warning as part of a category of detailed serialization-related warnings that could be optionally enabled (along with warning about serializable inner classes, etc.), but the exact nature of the desired warning would have to be considered carefully, which might affect its feasibility (does javac really want to be analyzing the contents of a "serialPersistentFields" declaration?). ###@###.### 2005-05-17 16:29:50 GMT