Enterprise Java

A clean approach to Wicket models

One of the core concepts of Apache Wicket web framework is the model and IModel as its programming interface. Wicket components rely heavily on models, which makes them important pieces of the architecture. Apache Wicket is stateful framework that stores the pages and their components to a page store that usually resides in the HTTP session. Components create the public facing view from the content of the models. Misusing models can cause awkward side effects, like pages not updating their content or huge memory consumption in your application. And the most issues with new Wicket users, from what I’ve seen, are with the correct use of the models. In this blog post I’ll try to explain how and what kind of models should be used in different use cases.

The most basic of the Wicket IModel implementations is the Model class. It is basically a simple placeholder for the model content. This suits fine for situations where the model content does not consume much memory and is more like a constant. A simple String could be a good candidate for Model’s content.

 IModel<String> name = new Model<String>("John");

You have to understand, that when you create a Model object its content stays the same even if the page containing the model is refreshed. This behavior is caused by the use of a static model. Dynamic models can change the actual content every time the value is asked from the model. Using a static model instead of a dynamic one is quite common mistake by new Wicket users. If the concept of static and dynamic models is not clear to you, you should check chapter 4 Understanding models from the book Wicket in Action.

IModel<Date> date = new Model<Date>() {
    @Override
    public Date getObject() {
        return new Date();
    }
};

The dynamic date model above is created as an anonymous class from Model by overriding the getObject() method. The model will always return a fresh copy of Date that contains the current time.

Wicket is stateful web framework and the models are stored usually in the user’s HTTP session. The data in the model is most likely fetched from database or through some web service. If we use the static model approach, we will eat up a lot of memory soon and will not achieve a fresh view from the data source if the page is reloaded. If we decide to use a dynamic model like we did with the Date object, we might end up making a lot of database searches or web service calls within one page load. The anonymous inner class is not nice looking code either. Wicket has a built in solution for this problem, LoadableDetachableModel that caches the content of the model until it is safe to discard, providing an efficient but still dynamic model.

public class PersonModel extends LoadableDetachableModel<Person> {
 
    private Long id;
    private PersonService personService;
 
    public PersonModel(final Long id, final PersonService personService) {
        super();
        this.id = id;
        this.personService = personService;
    }
 
    public PersonModel(final Person person, final PersonService personService) {
        super(person);
        this.id = person.getId();
        this.personService = personService;
    }
 
    @Override
    protected Person load() {
        return personService.findById(id);
    }
}

The above example constructs a loadable and detachable model for loading a single person by its unique identifier. The model has two constructors for a reason. One to create a lazy loaded model in detached state that will load the content when the getObject() method is called first time, and one to create a model in attached state that does not require a call to PersonService when the getObject() method is called. It is good practice to provide these 2 constructors for all LoadableDetachableModels. You can create a model in attached state when you already have the content or create it in detached state when only the identifier is available.

The caveat of loadable detachable models is the private fields of the model. Wicket stores the model along with the components in a page store and that might require serialization of the model. When the model is serialized, also the private fields are serialized (the actual content is detached). Our id field is not a problem because it’s serializable, but the PersonService might be a problem. Usually the service layer’s interfaces are not serializable by default. There are at least two decent solutions to this issue: either make your services serializable, or better one, wrap the service in a serializable proxy. The proxy behavior can be achieved for example with integrations to different dependency injection frameworks, eg. Spring (wicket-spring) or Guice (wicket-guice). The integration modules make sure that the service proxies are serializable when you inject them.

public class ProfilePage extends WebPage {
 
    @SpringBean
    private PersonService personService;
 
    public ProfilePage(final PageParameters parameters) {
        super(parameters);
 
        Long id = parameters.get("id").toLongObject();
        IModel<Person> personModel =
                new PersonModel(id, personService);
        add(new ProfilePanel("profilePanel", personModel));
    }
}

The above example uses wicket-spring integration to inject the person service to the desired page. The @SpringBean annotation provides a serializable proxy, so when we create the person model, we don’t need to worry about the serialization of the service. Wicket does not allow constructor injection, because all the injection magic actually happens when we call the super() constructor. This means that we have the injected values initialized after the base constructor of Component is finished. Just remember to use serializable identifiers or locators for the data and use serializable proxies for the services.

Normally in MVC web frameworks the view layer uses some kind of data transfer objects to build the view. DTOs are composed and inherited to create different kind of views. Building the factories or mappers for those objects can be error prone or frustrating. Wicket provides a different solution to this issue. In Wicket, you can think that the IModel interface works like a relational database view that allows you to show the desired parts of the domain in different ways.

public class PersonFriendsModel extends AbstractReadOnlyModel<String> {
 
    private IModel<Person> personModel;
 
    public PersonFriendsModel(final IModel<Person> personModel) {
        super();
        this.personModel = personModel;
    }
 
    @Override
    public String getObject() {
        Person person = personModel.getObject();
        Iterable<String> friendNames =
                Iterables.transform(person.getFriends(),
                        new PersonNameFunction());
        return person.getName()
                + "'s friends are "
                + Joiner.on(", ").join(friendNames);
    }
 
    @Override
    public void detach() {
        personModel.detach();
    }
 
    private class PersonNameFunction implements Function<Person, String> {
        public String apply(final Person input) {
            return input.getName();
        }
    }
}

Here we build a model that could compose the PersonModel we created earlier. We use it as a source to build a nice list of the person’s friends. The model we are extending is the AbstractReadOnlyModel that Wicket offers to us. It is basically a normal model, but does not allow setting the model content. This makes perfect sense, because we are building a joined String and it would be awkward to parse a similar list and set the person’s friends from that list. We only use this model for read only purposes, to show the list of friends in the view. You can see the view analogy here, we are still using the same Person domain model, but exposing a custom view from it with help of a model. Notice that we delegate the detach method to the composed model. This makes sure that if we don’t have direct reference to the composed model in any component, we are still able to detach it from the friends model. Calling the detach() method multiple times does no harm, so it’s safe to use even from multiple components.

We created only a simple example of model composing. You should explore the Wicket’s built in model implementations and spend some time figuring how you can create reasonable models from your domain model with them. Just remember one thing: compose and extend models, not the domain objects.

The last thing I will talk about is the property models. They are widely used in many Wicket applications, and even Wicket in Action book encourages to use them, but they have some unwanted features. Property models are fast to code and easy to use, but they make your code “stringly typed”. And this is something we don’t want in type safe language like Java.

PropertyModel<String> nameModel =
        new PropertyModel<String>(personModel, "name");

We create a model from the person’s name using a PropertyModel. The name model can use either straight Person object or an IModel that provides us the person. This feature can be achieved by implementing the Wicket’s IChainingModel interface. We have two issues here though. First one is the type of the name model. We define that the name must be String, but actually the compiler cannot make sure that name is bound to a String getName() JavaBean property. The second issue comes from refactoring, we use a String value to define the property name. If you refactor the Person object with your IDE and hange the getName() method to getLastName(), your application will broke and again the compiler cannot notice this.

Let’s stop here for a while to look at the IChainingModel interface. Its main purpose is to allow using of a plain object or a chained model as the model’s content. The PropertyModel could be used with a model that provides a person or with plain person object. If you look at the PropertyModel’s source code, you notice that implementing the IChainingModel requires casting and, in my opinion, boiler plate code. The PersonFriendsModel we created earlier could be refactored to implement IChainingModel so that instead of taking only a model in as the content, it would also support taking a person straight in. Is this really necessary? Not really. If we want to use plain person, we could create a new static model from the person providing us the same functionality as IChainingModel would provide.

CompoundPropertyModel adds even more magic to the model handling. It serves as root model for many components that can bind automatically to it by matching the property name to the component id.

public class PersonForm extends Form<Person> {
 
    public PersonForm(final String id, final IModel<Person> personModel) {
        super(id, new CompoundPropertyModel<Person>(personModel));
 
        add(new TextField<String>("name"));
        add(new TextField<Integer>("age"));
    }
}

Here we create a form to show input fields for the person’s name and age. There is no model attached to either text field, but we are still able to bind the “name” component to the person’s name and the “age” component to the person’s age. The compound property model we created in the constructor is the root model for the form and automatically binds the form components to the object’s properties by the component ids. The same issues apply with the compound property model that apply with the property model, but we even add one more. Now we lock the component id straight to the property name. This means that we have a dependency from the HTML template straight to the domain objects property name. This does not sound very reasonable.

It is up to you if you want to use property models, but in my opinion they should be avoided due to the issues explained earlier. There are projects like bindgen-wicket that try to achieve the behavior of property models without losing the type safety. But even bindgen does not work that well with refactoring. How we implement the name model in a type and refactoring safe way then?

public class NameModel implements IModel<String> {
 
    private IModel<Person> personModel;
 
    public NameModel(final IModel<Person> personModel) {
        this.personModel = personModel;
    }
 
    @Override
    public String getObject() {
        return personModel.getObject().getName();
    }
 
    @Override
    public void setObject(String object) {
        personModel.getObject().setName(object);
    }
 
    @Override
    public void detach() {
        personModel.detach();
    }
}

The model has a lot more lines than the property model. Yes, that is true, but do you want to lose type safety and refactoring features and potentially break your application very easily. The model is in different file so you can still use it as a one liner, so there is no difference if you use property model or the model we just created. And you can always remember the fact that Java is just very verbose language.

Wicket also provides us ResourceModel and StringResourceModel that provide a powerful tool of creating localized content for your components. I will not discuss them in this post, because Wicket in Action book has good reference for those. I tried to bring up some real life examples how to use different kind of models and what their purpose is. I hope this gave you some more knowledge about Wicket models and how they should be used properly.
 

Reference: A clean approach to Wicket models from our JCG partner Tapio Rautonen at the RAINBOW WORLDS blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Kate
Kate
10 years ago

MOAR! Nice to see new post on Wicket again. It seemed like no-one was using this framework anymore.

RobAu
RobAu
9 years ago

I prefer the lamba4j approach. See here: https://cwiki.apache.org/confluence/display/WICKET/Working+with+Wicket+models (somehere near the bttom)

Back to top button