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,IModel userMdl) {
	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,IModel userMdl) {
	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,IModel userMdl) {
	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,IModel userMdl) {
	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