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