The first problem, I had entire lists that were cached. This list was drawn from the database, and used over and over as a complete list, so it made sense to cache the list as a whole. I chose to use java.util.List as the interface for the lists I was returning, but quickly realized that there is no immutable List in Java, or at least none that I found (know of any?). So I decided to roll my own.
I started by creating a class called ImmutableList which extends java.util.ArrayList, and has a constructor which takes a List that it is to secure. I am using Java 5 with support for Generics, where "E" is the object type to be stored in the List (for those still using Java 1.4 you can for the most part replace "E" with "Object").
public ImmutableList (List<E> list)
{
super(list);
}
Next I went through and wrote methods to override methods that did stuff to the list. I have all of these methods throwing a run-time exception that I created.
public boolean add (E o)
{
throw new ImmutableRuntimeException();
}
public boolean remove (Object o)
{
throw new ImmutableRuntimeException();
}
...etc...
But there is a problem, the List interface has methods that return a java.util.Iterator object or a java.util.ListIterator object. Both of these iteration object s have the ability to alter the underlying list, so this too needed to be locked down. I made these private inner classes so that they could only be created by the ImmutableList. Every method that allowed changes to the List will throw a run-time exception. Below is what the immutable version of the Iterator looks like.
private class ImmutableIterator implements Iterator<E>
{
private Iterator<E> iter;
public ImmutableIterator (Iterator<E> iter)
{
this.iter = iter;
}
public boolean hasNext ()
{
return iter.hasNext();
}
public E next ()
{
return iter.next();
}
public void remove ()
{
throw new ImmutableRuntimeException();
}
}
This locks down the List, but don't forget to also lock down the objects inside of the List. When you get done, it should be impossible to write to the object or any object that it holds. Don't leave it to convention to enforce policy, enforce policy with the language. If you do this, and the system starts to misbehave, you have one place to look. Of course, the more you do this, the less likely a bug will be introduced into the system. We are human, we make mistakes, so why not make it easier for us by enforcing some rules.
Happy coding.
2 comments:
Googling for immutable list java returns the library you wanted - Collections.unmodifiableList. =)
I did Google it... Really! :)
I have no idea why that didn't come up in my searching. Thanks for the link.
...In any case, I think the underlying message is still valid, lock things down tight. The bigger the system, the more you need to run a tight ship.
Post a Comment