views:

520

answers:

3

I am very curious about the possibility of providing immutability for java beans (by beans here I mean classes with an empty constructor providing getters and setters for members). Clearly these classes are not immutable and where they are used to transport values from the data layer this seems like a real problem.

One approach to this problem has been mentioned here in StackOverflow called "Immutable object pattern in C#" where the object is frozen once fully built. I have an alternative approach and would really like to hear people's opinions on it.

The pattern involves two classes Immutable and Mutable where Mutable and Immutable both implement an interface which provides non-mutating bean methods.

For example

public interface DateBean {
    public Date getDate();
    public DateBean getImmutableInstance();
    public DateBean getMutableInstance();
}

public class ImmutableDate implements DateBean {
    private Date date;

ImmutableDate(Date date) {
 this.date = new Date(date.getTime());
}

public Date getDate() {
 return new Date(date.getTime());
}

 public DateBean getImmutableInstance() {
  return this;
 }

 public DateBean getMutableInstance() {
  MutableDate dateBean = new MutableDate();
  dateBean.setDate(getDate());
  return dateBean;
 }
}

public class MutableDate implements DateBean {
    private Date date;

public Date getDate() {
 return date;
}

public void setDate(Date date) {
 this.date = date;
}

public DateBean getImmutableInstance() {
 return new ImmutableDate(this.date);
}

 public DateBean getMutableInstance() {
  MutableDate dateBean = new MutableDate();
  dateBean.setDate(getDate());
  return dateBean;
 }
}

This approach allows the bean to be constructed using reflection (by the usual conventions) and also allows us to convert to an immutable variant at the nearest opportunity. Unfortunately there is clearly a large amount of boilerplate per bean.

I am very interested to hear other people's approach to this issue. (My apologies for not providing a good question, which can be answered rather than discussed :)

+1  A: 

Some comments (not necessarily problems):

  1. The Date class is itself mutable so you are correctly copying it to protect immutability, but personally I prefer to convert to long in the constructor and return a new Date(longValue) in the getter.
  2. Both your getWhateverInstance() methods return DateBean which will necessitate casting, it might be an idea to change the interface to return the specific type instead.
  3. Having said all that I would be inclined to just have two classes one mutable and one immutable, sharing a common (i.e. get only) interface if appropriate. If you think there will be a lot of conversion back and forth then add a copy constructor to both classes.
  4. I prefer immutable classes to declare fields as final to make the compiler enforce immutability as well.

e.g.

public interface DateBean {
    public Date getDate();
}

public class ImmutableDate implements DateBean {
    private final long date;

    ImmutableDate(long date) {
       this.date = date;
    }

    ImmutableDate(Date date) {
       this(date.getTime());
    }

    ImmutableDate(DateBean bean) {
       this(bean.getDate());
    }

    public Date getDate() {
         return new Date(date);
    }
}


public class MutableDate implements DateBean {
    private long date;

    MutableDate() {}

    MutableDate(long date) {
       this.date = date;
    }

    MutableDate(Date date) {
       this(date.getTime());
    }

    MutableDate(DateBean bean) {
       this(bean.getDate());
    }

    public Date getDate() {
        return new Date(date);
    }

    public void setDate(Date date) {
        this.date = date.getTime();
    }

}
Michael Rutherfurd
Thanks for your comments. I agree that the copy constructor is a significant improvement over the interface factory methods. The note on final members is well taken. Cheers.
Francis Stephens
A: 

I use interfaces and casting to control the mutability of beans. I don't see a good reason to complicate my domain objects with methods like getImmutableInstance() and getMutableInstance().

Why not just make use of inheritance and abstraction? e.g.

public interface User{

  long getId();

  String getName();

  int getAge();

}

public interface MutableUser extends User{

  void setName(String name);

  void setAge(int age);

}

Here's what the client of the code will be doing:

public void validateUser(User user){
  if(user.getName() == null) ...
}

public void updateUserAge(MutableUser user, int age){
  user.setAge(age);
}

Does it answer your question?

yc

yclian
I assume you mean for the MutableUser interface to extend the User interface? Needless to say this still requires a concrete class. The down side is that it opens you to "Immutable" being changed mutable by a simple cast which is likely not what you want.
Michael Rutherfurd
While it is true that the User interface does not provide methods for mutating a User object that is not on the face of it as strong a guarantee of immutability as I would ask for from this pattern.
Francis Stephens
Although I think your approach does provide a good working solution where the type (User) implicitly suggests that User should not be mutated. In many contexts this is probably sufficient. Thanks.
Francis Stephens
True that. The weakness of this approach is that rules can be easily violated with casting. The internal code presumably won't be violating it but the client's code will. The best you can do is to control the type at method level as shown above.
yclian
+1  A: 

I think I'd use the delegation pattern - make an ImmutableDate class with a single DateBean member that must be specified in the constructor:

public class ImmutableDate implements DateBean
{
   private DateBean delegate;

   public ImmutableDate(DateBean d)
   {
      this.delegate = d;
   }

   public Date getDate()
   {
      return delegate.getDate();
   }
}

If ever I need to force immutability on a DateBean d, I just new ImmutableDate(d) on it. I could have been smart and made sure I didn't delegate the delegate, but you get the idea. That avoids the issue of a client trying to cast it into something mutable. This is much like the JDK does with Collections.unmodifiableMap() etc. (in those cases, however, the mutation functions still have to be implemented, and are coded to throw a runtime exception. Much easier if you have a base interface without the mutators).

Yet again it is tedious boilerplate code but it is the sort of thing that a good IDE like Eclipse can auto-generate for you with just a few mouse clicks.

If it's the sort of thing you end up doing to a lot of domain objects, you might want to consider using dynamic proxies or maybe even AOP. It would be relatively easy then to build a proxy for any object, delegating all the get methods, and trapping or ignoring the set methods as appropriate.

Chris
That is a very good idea. That fits the problem very elegantly. Cheers Chris.
Francis Stephens