Sunday, October 01, 2006

Correction for read-only Java objects

The problem

In my own code I sometimes bypass a getter for a final field in favor of direct field access for struct-like classes:

public class BigFoot {
    public final int shoeSize;

    public BigFoot(final int shoeSize) {
        this.shoeSize = shoeSize;
    }
}

I figure: why not? As the field is final there is no need for modifying behavior in a getter method. This seems ideal for data transfer objects (DTOs).

However Miles Barr points out the big flaw with this idea. It is subtle and has to with how the Java compiler deals with direct field access. Miles explains the problem as well as anyone and has a clear example. Fundamentally, you lose polymorphism for shadowed variables and bad things result.

The solution

The mistake for my DTO was not carrying the notion of simple struct-ness to its full conclusion. How much sense does it make to extend DTOs?

public final class BigFoot {
    public final int shoeSize;

    public BigFoot(final int shoeSize) {
        this.shoeSize = shoeSize;
    }
}

If the class is marked final then there will never be a problem with shadowing fields in subclasses.

A caveat

Sometimes I want to extend my DTOs when I have a set of similar data to represent and extract out the common fields in to a base class.

But this is an implementation detail. Logically there is no class relationship among the DTOs and the problem with shadowed fields is one which exposes an implementation detail to the user.

So don't do that.

No comments: