1

I have a Java application where the domain layer is decoupled from the UI by controllers. The problem is that these controllers can return domain objects, and can have domain objects as parameters.

Some of these returned domain objects are mutable, and this is what I want to prevent. I want it impossible for the UI (or future UI's) to directly modify the domain without accessing the controllers.

I tried two options:

  • In the first one I made sure that each class implemented an 'Unmodifiable' interface which contained only getters. And if I needed to return an object to the UI, I returned its 'Unmodifiable' interface. So that the UI could only view the getters. The problem with this that they still can be cast easily to the original object and access is gained. At first I thought that this level of security was good enough, but it happend that someone accidentally casted some objects and used them in an incorrect way, and integrity was breached.

  • In the second one I tried to provide unmodifiable wrappers for each object that could be returned. But the problem is that these returned objects can be used as parameters for methods in the controllers and so they needed to be unwrapped in the controllers. I tried to make the uwrap() methode package-private, but then I have to put every specific wrapper class in the same package with the controllers and this is a bit inconvenient.

EDIT: 3th option:

  • (With thanks to vic) In the third option the object is wrapped by a unmodifiable wrapper, but can't be unwrapped by this wrapper. Each Unmodifiable is linked to its modifiable object in a Hashmap. So 'unwrapping' is done by getting the modifiable object that is linked to the unmodifiable object.

Does anyone know or has some ideas on how to make objects unmodifiable so they can be returned by a controller, and make it possible to make them modifiable again when they are passed back to the controllers?

Community
  • 1
  • 1
Peter
  • 746
  • 6
  • 22

2 Answers2

2

What if the controllers store privately the mutable versions of the objects and return immutable versions of it to the "outer world". The mutable versions will have some kind of unique id, and the controllers will be able to unwrap it by looking up in a Collection of some sort.

Vic
  • 21,473
  • 11
  • 76
  • 97
  • I was thinking about that myself, this is currently at the top of my list! The unique id could be the hashcode of the object, and then a HashMap can be used as the collection. – Peter Feb 18 '12 at 14:48
  • 1
    If you go that route, watch out for memory leaks! Any element in the hashmap won't be eligible for GC. A `WeakHashMap` would help, but this approach requires some hand-waving about object lifecycle (I'm generally wary of WeakReference or WeakHashMap -- seems like a crutch to me). – yshavit Feb 18 '12 at 15:17
  • @yshavit I thought about that problem, but I didn't know about WeakHashMap, thanks for the hint, I look into it. – Peter Feb 18 '12 at 15:29
2

Go for the State design pattern which is an excellent choice to represent an object's state.

Basically, whenever the UI wants to display a domain object, the controller gives it an immutable DTO object representing a snapshot of the object itself. This will restrict the UI layer to have only immutable snapshots of your domain objects. When the UI wants to make changes to your domain objects, it sends immutable state objects to the controller which use them to internally modify the corresponding domain objects.

GETah
  • 20,922
  • 7
  • 61
  • 103
  • But I don't want to use immutable snapshots. I like to use Unmodifiable objects, that can still be changed by the domain-logic, but can't be changed by the user. Changes by the domain-logic should be viewable to holders of a Unmodifiable object. – Peter Feb 18 '12 at 15:02
  • @Xochipilli You can always have a check in every method of your domain object. The check will throw an exception in case the caller does not have enough rights to call that method. – GETah Feb 18 '12 at 15:11
  • I thought about that, but I quickly abandoned this idea because it seems to much work. To bad java doesn't have friend classes :( – Peter Feb 18 '12 at 15:24