Using the -Xcheckinit compiler option, the compiler creates a bitmap field that it uses to verify initialization.
public volatile int bitmap$0;
In accessories, the compiler checks the bitmap:
public int y(){ if ((this.bitmap$0 & 0x1) != 0){ return this.y; } throw new UninitializedFieldError("Uninitialized field: Test.scala: 2".toString()); }
In the constructor, the compiler updates the bitmap:
public XYPointWithRW(int x) { Product.class.$init$(this); this.y = 0; this.bitmap$0 |= 1; }
Note that it does not update the bitmap for constructor arguments, only for fields declared in the class. He does this because he assumes that you are calling the constructor and that these fields will be initialized immediately.
However, when deserializing, the no-arg constructor of the first non-serializable superclass is called (Object in this case) instead of the one-arg constructor shown above. Then readObject is called. The above constructor is never called. Therefore, the bitmap is never updated. An accessory call would not succeed anywhere in its called, and not just in the readObject method.
To get around this, you must update the bitmap manually. I decided to do this from the readObject method. I set all the bits in the bitmap to 1, for example:
getClass.getField("bitmap$0").set(this, -1)
By setting all the bits to 1, it will work for all fields (up to 32 fields anyway ... what happens further than possible).
source share