[concurrency-interest] Joda-Time immutability

Gregg Wonderly gregg at cytetech.com
Tue Jun 21 09:13:29 EDT 2011

On 6/21/2011 3:11 AM, Mark Thornton wrote:
> On 21/06/11 07:27, Mark Thornton wrote:
>> On 20/06/11 11:33, Stephen Colebourne wrote:
>>> In Joda-Time way back when we structured the code in a complex manner
>>> and then claimed immutability. This is causing difficulty to try and
>>> obey proper immutability standards, and I'd like any ideas on fixes.
>>> Consider the "immutable" class DateTime. The hierarchy is as follows:
>>> AbstractInstant
>>> AbstractDateTime
>>> BaseDateTime
>>> DateTime / MutableDateTime
>>> https://github.com/JodaOrg/joda-time/tree/master/src/main/java/org/joda/time
>>> https://github.com/JodaOrg/joda-time/tree/master/src/main/java/org/joda/time/base
>>> The two Abstract prefixed classes are not an issue, as they just share
>>> code and contain no state. However the BaseDateTime contains all the
>>> state (and DateTime/MutableDateTime contain no state).
>>> As a result of this (bad) design, the instance variables in
>>> BaseDateTime are not final (as they need to be mutated by the
>>> MutableDateTime subclass). The DateTime ("immutable") subclass is thus
>>> storing its state in regular mutable variables in BaseDateTime. Under
>>> the memory model, claiming DateTime as immutable is wrong.
>> A possible solution:
>> Make the fields in BaseDateTime final.
>> DateTime is left unchanged.
>> Duplicate the fields in MutableDateTime with getter/setters referring to the
>> new (mutable) fields.
>> Add a readObject method to MutableDateTime which calls
>> ObjectInputStream.readFields. If the new fields are present (test using
>> GetFields.defaulted) then we are restoring from a serialization of the new
>> form of the class; just restore them as usual. If the fields are missing, then
>> the serialized form was from the old class, in this case copy the values from
>> the immutable values in BaseDateTime.
>> Note I have not tried this.
>> Mark Thornton
> An even simpler method would modify MutableDateTime as follows
> public class MutableDateTime extends BaseDateTime {
> private long iMillis;
> private Chronology chronology;
> private void readObject(ObjectInputStream in) throws ... {
> iMillis = super.getMillis();
> chronology = super.getChronology();
> in.defaultReadObject();
> }

When there is an object reference involved in this kind of change, we've always 
just done

private void readObject( ObjectInputStream in ) throws ... {


	// If this is the first time to deserialize with the new
	// mutable fields in place, copy the values from the old
	// final fields.
	if( chronology == null ) {
		iMillis = super.getMillis();
		chronology = super.getChronology();

This is a little easier to understand so that people don't wonder why you are 
doing things out of order.  A comment on the other version would perhaps detail
what is important about the ordering of statements there too.

Gregg Wonderly

More information about the Concurrency-interest mailing list