Many times on the Wicket user list, we hear questions like “How do I return a different value when my model object is null?”, or “how do I make a label that says ‘none’ when the model object is null?”, or “How do I make a Label that capitalizes all it’s text?”…. You get the idea. Typically, the gut reaction is to do something like override getConverter in the Label or onComponentTagBody and sort of abuse that facility to change what value the Label uses. This works, but it isn’t reusable. One of the greatest powers of Wicket is creating reusable pieces of code that can be used anywhere in your application.

A great way to create a reusable piece of code to cover this scenario is to use nested models. If you are familiar with Wicket, you know that models, or implementations of IModel, are basically data locators - an abstraction layer that the component uses to locate it’s data. One power that this layer of abstraction gives you is that a component doesn’t need to know where it’s data came from. And, one model can use another model and add on to it’s behavior by composition. Let’s look at some code for a couple of examples.

EXAMPLE ONE - You want to provide a different value for the case when your model object is null

public class DefaultWhenNullModel implements IModel {

   private static final long serialVersionUID = 1L;

   private final IModel mNestedModel;
   private final T mDefaultValue;

   public DefaultWhenNullModel(IModel nestedModel, T defaultValue) {
      mNestedModel = nestedModel;
      mDefaultValue = defaultValue;
   }

   public T getObject() {
      T val = mNestedModel.getObject();
      return val == null ? mDefaultValue : val;
   }

   public void setObject(T object) {
      mNestedModel.setObject(object);
   }

   public void detach() {
      mNestedModel.detach();
   }
}

EXAMPLE TWO - You want to capitalize the text in a label

public class CapitalizedStringModel implements IModel {

   private static final long serialVersionUID = 1L;

   private final IModel mNestedModel;

   public CapitalizedStringModel(IModel nestedModel) {
      mNestedModel = nestedModel;
   }

   public String getObject() {
      String value = mNestedModel.getObject();
      return value.toUpperCase();
   }

   public void setObject(T object) {
      mNestedModel.setObject(object);
   }

   public void detach() {
      mNestedModel.detach();
   }
}

Use of these:

new Label("mylabel", new CapitalizeStringModel(new PropertyModel(user, "username")));

As you can see, both examples are very similar. You can take this further by creating a class like AbstractNestedModel<T> (implementing IModel<T>) that takes care of holding the nested model and detaching the nested model, etc. Then you could create these classes with only a getObject() method being implemented per type of model.

Why is this better?

Quite simply, because you can use this anywhere. For instance, if you did this in a Label instead, you could only use it where you use labels. But since models are used by all components that want to display data, you can reuse this for any component, not just a label. For instance, you could use this in MultiLineLabel or a TextField (you may want to add functionality to setObject for a TextField since it is read AND write).

Hopefully you found this brief tutorial helpful. If you are looking for professional Wicket training or support, check out http://www.wickettraining.com.