Thursday, June 30, 2011

Defensive copies

One of the building blocks of Domain Driven Design (DDD) is the Value Object: an object that contains attributes but has no conceptual identity. Value Objects should be treated as immutable.

Consider the following class:

public final class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        this.start = start;
        this.end = end;
    }

    public Date getStart() {
        return start;
    }

    public Date getEnd() {
        return end;
    }
}

This is a common example of the Value Object. What is wrong with this class?

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(81); //modifies internals of p!

Just because the Period class has no mutator methods it does not mean we can not change its state. In the example above we kept a reference to a mutable object. If we want to prevent this from happening we have to make a defensive copy of each mutable parameter to the constructor:


public Period(Date start, Date end) {
    this.start = new Date(start);
    this.end = new Date(end);
}

Are we there yet? Not really.

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.getEnd().setYear(96); //modifies internals of p!

The common mistake made was exposing a field which is mutable. By returning defensive copies of mutable internal fields our Value Object is finally fixed.

public Date getStart() {
    return new Date(start);
}

public Date getEnd() {
    return new Date(end);
}

Defensive copying can have a performance penalty associated with it. In this particular case my best advice would be to consider Joda-Time's DateTime as an immutable replacement for Date.

In general, you should, where possible, use immutable objects as components of your own objects so that you that don't have to worry about defensive copying. If you do use mutable objects you should think twice before returning a reference to an internal component. Chances are, you should return a defensive copy instead. The same goes for a mutable object entering your internal data structure in the constructor.
If the class trusts its clients and the performance penalty for defensive copying would be too high you may accept or return a reference to a mutable object but be aware - subtle bugs can show up regardless what you wrote in your documentation about your class.

If there is any validation in your constructor it should happen after making the defensive copies in order to eliminate the window of vulnerability between the time the parameters are checked and the time they are copied.


public Period(Date start, Date end) {
    this.start = new Date(start);
    this.end = new Date(end);

    //run validation on this.start and this.end
}

Thursday, June 23, 2011

Reification in Java

"I still get unchecked warnings!" - a sentence I hear from time to time when I am sitting close to people trying to use generics. Every unchecked warning represents the potential for a ClassCastException at run-time. Do your best to eliminate these warnings if possible - which is not always the case. The more experience you acquire with generics, the fewer warnings you’ll get, but don’t expect newly written code that uses generics to compile cleanly.
Why do we get these warnings? What's wrong with generics? In short the answer is: they are not reified. In Java a type is reifiable if the type is completely represented at runtime, that is, if erasure does not remove any useful information.

A type is not reifiable if it is one of the following:
  • A type variable (such as T)
  • A parameterized type with actual parameters (such as List<Number>, ArrayList<String>, or Map<String, Integer>)
  • A parameterized type with a bound (such as List<? extends Number> or Comparable<? super String>)
Generics are implemented using erasure, in which generic type parameters are simply removed at run-time. That doesn't render generics useless, because you get type checking at compile-time based on the generic type parameters, and also because the compiler inserts casts in the code (so that you don't have to) based on the type parameters.


        Map<String, String> countryCodes = new HashMap<String, String>();
        countryCodes.put("US", "United States");
        String country = countryCodes.get("US");

If you compile the source above and then de-compile the generated class file you will see that they are not the same:


        Map countryCodes = new HashMap();
        countryCodes.put("US", "United States");
        String country = (String) countryCodes.get("US");

You should note two things in the code above:
  1. the type parameter "<String, String>" is missing
  2. (String) countryCodes.get("US"); typecast is added
This is done by the java compiler while compiling java source code to byte code. This process is called type erasure.
Generics are implemented using erasure as a response to the design requirement that they support migration compatibility: it should be possible to add generic type parameters to existing classes without breaking source or binary compatibility with existing clients.

While solving one set of problems, erasure adds a set of its own problems.

For a type parameter T, you can't
  • write a class literal T.class.
  • use instanceof to test if an object is of type T
  • create an array of T
  • write class literals for generic types like List<String>.class
  • test if an object is an instanceof List<String>
  • create an array of List<String>
Being unable to create an array of a parameterized type also means that you can get confusing warnings when using varargs methods in combination with generic types. This is because every time you invoke a varargs method, an array is created to hold the varargs parameters. If the element type of this array is not reifiable, you get a warning.


    public static <T> List<T> toList(T... item) {
        List<T> list = new ArrayList<T>();
        for (T element : item) list.add(element);
        return list;
    }

    public static <K> List<K> singleton(K element) {
        return toList(element); // unchecked warning
    }

There is little you can do about these warnings other than to suppress them, and to avoid mixing generics and varargs in your APIs.