I vote for solution 3: postpone the onInitialize call, possible to the first
Component#configure execution. Then the problem of initialization code being
executed for not  fully constructed components go away.
If it is really important to have a callback method for path cognizant
components, than the API can be improved adding one more method like the awt
Component#addNotify, but with one change: this method needs to be called
again if the component is remove / re added and it will not be a good place
to add children.

- 1 for solution 2, it is up to user decide how to code objects, the related
problems in this thread can be addressed in different way, like I voted
before.

On Tue, Mar 8, 2011 at 8:11 AM, Maarten Billemont <lhun...@gmail.com> wrote:

> Dear fellow wicket users,
>
> Following is a call for your opinion and a vote on how Wicket should behave
> with regards to post-constructing components in 1.5.  The final solution
> that is chosen will affect the way you construct your components and your
> component hierarchies.
>
>
>
> First, some background on what onInitialize is and why you should be using
> it.
>
> THE PROBLEM
>
> Historically, we've generally used our component constructors to build our
> component's hierarchy.  We call add() to put new components in our custom
> component from our component's constructor:
>
> public class MyPanel extends Panel {
>
>    private final IModel<String> name = Model.of();
>
>    public MyPanel(String id) {
>
>        add(new TextField<String>("name", name));
>    }
> }
>
> This can cause problems, however, when initializing a component requires
> knowledge of the component's markup, or requires that the component's path
> in the hierarchy is known (during construction, the component is not yet
> added to any parent component).
>
>
> THE SOLUTION
>
> onInitialize was introduced to Component.  This gives us a place to
> initialize our component's hierarchy after our component has been added to
> its parent.  As a result, our component has a path to its page, making
> markup, parent and sibling components accessible.
>
>
> THE BAD
>
> The downside of initializing your component hierarchy in onInitialize as
> opposed to from the constructor, are:
>
> 1. You need to move all your component hierarchy initialization code into a
> separate method.  Usually, this is trivial work (cut/paste), but it is work
> that needs to be done nonetheless.
> 2. You cannot put your components in final instance fields anymore.
> 3. You should never do anything with components from custom methods.  You
> should only ever reference your components directly from overridden wicket
> methods, such as onConfigure, onBeforeRender, onSubmit, etc.
>
> A little more on #3:
>
> If you add custom methods to your component, eg.
>
> void makeRequired() {
>    nameField.setRequired(true);
> }
>
> You allow things like: new MyPanel().makeRequired();
> That would throw a NullPointerException, since nameField is no longer
> initialized in the constructor, but much later, before the component first
> gets rendered.
>
> I would argue, though, that any custom methods that touch components are to
> be avoided at all cost.  Component behaviors should never be touched except
> from wicket lifecycle methods (you probably want onConfigure) or right after
> you construct it:  add(new TextField<String>("name",
> name).setRequired(true));  If you need a custom method such as makeRequired,
> it shouldn't touch components, it should set state that gets used by
> onConfigure:
>
> void makeRequired() {
>
>    this.required = true;
> }
>
> void onConfigure() {
>
>    setRequired(required);
> }
>
> (Obviously, the example is rather silly..)
>
>
>
> Fast-forward to https://issues.apache.org/jira/browse/WICKET-3218, it
> seems onInitialize has a problem.
>
> THE PROBLEM
>
> With regard to pages, if you add a component to a page from the
> constructor, onInitialize is invoked immediately.  As a result, onInitialize
> code is ran even though your instance hasn't been fully constructed yet.
>  This is bad.
>
> The real issue here is that we can combine component hierarchy
> initialization with constructors and onInitialize in a single class.
>  However, doing so causes dangerous situations.  We really should do only
> one, not both at the same time.
>
>
> THE SOLUTIONS
>
> This is where we need your vote.  Currently, two proposed solutions exist:
>
> 1. Make onInitialize final for all Pages.  As a result, onInitialize will
> still get called when the page is constructed and components are added, but
> you won't be able to use it, avoiding the risk of you using it in a manner
> that requires your instance to be constructed.
>
> 2. Make adding components from the constructor illegal.  This would have to
> be by means of a runtime exception thrown whenever you try to add components
> to the hierarchy from the constructor.
>
>
> THE GOOD
>
> 1. This will be least painful for existing code.  In all components, you
> can still mix constructor an onInitialize use, in pages, you can't use
> onInitialize, but in all likelihood, the largest amount of existing wicket
> code out there still uses constructors to create component hierarchies.
>
> 2. The safer onInitialize will always and consistently be used for any
> component hierarchy construction.  This also requires the good code habits
> that you shouldn't be doing anything with your components outside of wicket
> lifecycle methods.
>
>
> THE BAD
>
> 1. Mixing constructor and onInitialize usage, whether it's within one class
> or between different classes in your type and component hierarchy, is and
> will always be dodgy.  You really shouldn't do it.  Also, to future-proof
> your code, you should really already be moving your initialization code into
> onInitialize.  Additionally, this introduces an API inconsistency: For
> pages, you cannot use onInitialize, for everything else, you should.  That's
> not very intuitive.  Additionally, it makes refactoring pages into panels
> and back a real pain (we've had to do this quite often already).
>
> 2. Checking for add() usage with a runtime exception is not very neat.
>  You'll only notice your mistake at runtime (albeit, very soon.  And during
> your migration to 1.5, you should expect more trouble than just this).
>  Probably the biggest down-side is that a lot of people will need to move
> code around, from constructors into onInitialize (it can be argued that you
> really should be doing this anyway).
>
>
> REFERENCES
>
> The original discussion on the onInitialize issue with Pages:
>
> http://mail-archives.apache.org/mod_mbox/wicket-dev/201012.mbox/%3c1291238699.1749.1408166...@webmail.messagingengine.com%3E
>
> The JIRA issue:
> https://issues.apache.org/jira/browse/WICKET-3218
>
> Please refer to these if you're not entirely sure about the arguments of
> either side.
>
> Cast your vote for the future shape of wicket's component hierarchy
> initialization API.
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
> For additional commands, e-mail: users-h...@wicket.apache.org
>
>


-- 
Pedro Henrique Oliveira dos Santos

Reply via email to