The Partially Constructed Object Dilemma
Wicket naturally lends itself to object-oriented representations of web pages, and one aspect of this approach is using inheritance to pull behavior common to a set of pages into a superclass shared by those pages. For example, several pages might have a shared base class in
Template.java (with corresponding markup in
Template.html) which sets up a header and side navigation menu that is common to those pages.
A problem is encountered, however, when it comes to allowing subclasses to modify the base class behavior through method overrides. For example, let's assume the
Template has a header with the page title, and that this title changes per page. A plausible solution is to provide an abstract
getPageTitle method which subclasses will override. In the
Template constructor, it will add a label with the result of this method:
Let's also assume that a certain page subclass of
Template wants the title in question to depend upon data passed in through
PageParameters at construction:
The problem we encounter is that the code to look up
myObject above has not yet run when
getPageTitle() is invoked in the constructor of
Template. In general, invoking overridable methods from a java constructor is considered bad practice, because the object in question has not necessarily been completely constructed (meaning that subclass constructor(s) have not yet run) when a base class constructor is being invoked.
There is no consensus in the wicket community on a standard pattern for solving this problem.
This is not entirely true. The core-devs have a consensus - which is to use Component#onBeforeRender() to construct subclass-driven dynamic component hierarchies. This approach is demonstrated towards the end of the page. - ivaynberg
. There are however a number of typical solutions.
This way the model implementation will be constructed at component construction time but its #getObject() will be called at component rendering time and the object we need will be already properly constructed.
Two-phase construction with an internal init() method called by subclasses
In this solution, an
init() method is declared in the base class, and subclasses are expected to:
init()to do any setup work, rather than doing that work in the constructor. The constructor is instead used to do setup of the model as well as the initialization of any local data that is dependent on PageParameter data.
super.init()as the first line in
init(), ensuring that init() mimics a constructor, so that the base class is set up before the subclass
init()at the end of their constructor(s), so that initialization is sure to happen
- Use Component#onBeforeRender to construct dynamic subclass driven hierarchy
There is no way to ensure that the above set up constraints are obeyed, but it nevertheless provides a simple solution to the partially-constructed-object problem without reliance on any class outside the pages in question. The above example, adopting this strategy, would look like:
One remaining problem with this strategy is that if
SomePage is itself subclassed, there is no clean way to ensure that init() is called after the most-derived class is constructed, and ensure that it is called only once, without testing and setting an
Two-phase construction with an init() method called by the base class
In this variant of the last solution, subclasses do no work in their constructor, but instead set up all data in an init() method that is called by the base class before it calls any other overridable methods:
This is very error prone. You must ensure that no overridable methods are called, which is not really doable as code is refactored, etc. In fact this is equivalent to calling overridable methods from the constructor
This variant does not rely on subclasses to call init(), and allows for subclasses existing subclasses of Template, provided all overrides of init() call super.init().
The problem of subclass-driven component hieararchies is easily solved using Component#onBeforeRender() callback and simple factory methods