Wicket Anti-Patterns: Avoiding Session Bloat
Wicket is a wonderful framework for building complex web applications. However, it is all too easy to hang your self with session use in Wicket. Wicket manages the session on your behalf so you don’t have to worry about UI state. Since every page is serialized to the session, you need to be extra careful with your entity graph so it does not get serialized with the page. Here are some anti patterns that I have personally stumbled upon.
Anti-Pattern #1.
public FooPanel(String id,IModeluserMdl) { super(id,userMdl); final User user = getModelObject(); IModel > model = new LoadableDetachableModel
>() { private static final long serialVersionUID = 1L; @Override protected List
load() { // A Stale User entity is now serialized with each page view // This can consume lots of session space if the user entity is large. return getWebSession().getUserService().getUserFriends(user); } }; }
Here is the correct way to do this
//IModel needs to be a LoadableDetachableModel! public FooPanel(String id,IModeluserMdl) { super(id,userMdl); final User user = getModelObject(); IModel > model = new LoadableDetachableModel
>() { private static final long serialVersionUID = 1L; @Override protected List
load() { User u = FooPanel.this.getModelObject(); return getWebSession().getUserService().getUserFriends(u); } }; }
The entity is fetched each page view, and NOT serialized with the page. The only thing that gets serialized is the fetching model.
Anti-Pattern #2.
public FooPanel(String id,IModeluserMdl) { super(id.userMdl); User user = getModelObject(); // Doh! user is not serialized with each page view, the PropertyModel holds a reference! add(new Label("name",new PropertyModel(user,"screenName"))); }
Here is the correct way to do this
public FooPanel(String id,IModeluserMdl) { super(id.userMdl); add(new Label("name",new PropertyModel(userMdl,"screenName"))); }
The PropertyModel holds a reference to the Model which fetches the User on each page view. That way the User object is always fresh and is not serialized with the page.
Anti-Pattern #3.
public FooPanel(String id,User user) { // The stale User object will be in your session // for the life span of the stateful page. super(id.new Model(user)); }
Here is the correct way to do this, though not very elegant.
public FooPanel(String id,User user) { super(id); final int id = user.getId(); setModel(new LoadableDetachableModel>() { @Override protected List
load() { return getUserDao().findById(id); } });
I hope these Wicket anti-patterns help you avoid the common pitfalls I have run into while developing
Fabulously40
Nice post!
I have a question about #1.
– Do you really need both using LoadableDetachable AND
User u = FooPanel.this.getModelObject();
Why adding this last line if the IModel if Detachable?
@gabriel
User u = FooPanel.this.getModelObject(); is referencing the passed userMdl. You don’t want to use the user object in the inner class directly or it fully gets serialized. This way only the lightweight userMdl gets serialized.
Wicket is full of surprises when it comes to session bloat if your not careful.
Nice post, however there is a problem in the layout of the article: the anti pattern #3 appears in the middle of a code box.
Very nice post! I know it’s quite a long time ago but it would be great if you share some more experience with Wicket antipatterns.
Nice post! It looks like that
final User user = getModelObject();
is redundant in the #1, the correct part of it.
Wanted also to ask, the line
final User user = getModelObject();
in #1 (the correct way) is redundant/obsolete and should be deleted. Correct?
Btw, thanks for the post. Very helpful! 🙂
Added these to the wiki for wicket best practices, hope you don’t mind. Thanks!