tapestry's component hierarchy is static and it separates state from actual objects via bytecode mangling. so there reloading works for a lot of cases, but will probably not work for the usecase martijn is talking about where you need to add new component and new state. there was a thread on tss about it when it first came out.
-igor On Thu, Nov 18, 2010 at 7:53 AM, James Carman <ja...@carmanconsulting.com> wrote: > Has anyone looked at how Tapestry solved this problem? I know they > did some work to make sure reloading happened in a "smart" way. > > On Thu, Nov 18, 2010 at 10:44 AM, Igor Vaynberg <igor.vaynb...@gmail.com> > wrote: >> invoking a constructor on a constructed class can lead to a lot more >> weirder state problems. dont forget, constructors dont just add class, >> they initialize state. invoking the constructor itself is not enough, >> you also need to invoke field initializations that are inlined, etc. >> at that point you might as well create a new instance of the page - >> since that is what you are essentially doing. >> >> -igor >> >> On Thu, Nov 18, 2010 at 4:52 AM, Martijn Dashorst >> <martijn.dasho...@gmail.com> wrote: >>> I've been trying out jrebel and wicket a couple of times, and I >>> thought it didn't work. It does, but the way Wicket development works >>> is undoing most of the benefits of using jrebel. >>> >>> The idea of jrebel is to replace hotswap with something that actually >>> works for normal development: adding methods, renaming them, creating >>> new (anonymous inner) classes etc, without having to restart your >>> application. And that works quite well... >>> >>> Until you start developing with Wicket. >>> >>> The problem is that our component hierarchy doesn't work well with >>> code replacement. A typical workflow is that you navigate in your >>> application to a page, and want to add a new component to it. So you >>> go into that class: >>> >>> public class LinkCounter extends WebPage { >>> public LinkCounter() { >>> } >>> } >>> >>> add a field: >>> >>> private int counter; >>> >>> add a label: >>> >>> public LinkCounter() { >>> add(new Label("counter", new PropertyModel<Integer>(this, >>> "counter))); >>> } >>> >>> <span wicket:id="counter"></span> >>> >>> add a link: >>> >>> public LinkCounter() { >>> ... >>> add(new Link<Void>("click") { >>> public void onClick() { >>> counter++; >>> }); >>> } >>> } >>> >>> <a href="#" wicket:id="click">Click me</a> >>> >>> All is well, and when you refresh the page (as long as you had a >>> bookmarkable link to it) it shows the new label and link. You click >>> the link and the URL changes from a bookmarkable URL to a link to a >>> specific instance. >>> >>> Now you want to add another link: >>> >>> add(new Link<Void>("minus") { >>> public void onClick() { >>> counter--; >>> } >>> }); >>> >>> Don't forget to modify the markup: >>> <span wicket:id="minus"></span> >>> >>> JRebel does its thing: adding the code to the constructor including >>> the anonymous inner class. You refresh your page and are presented >>> with a component not found exception: minus is added in the markup, >>> but not in the java code >>> >>> The problem is that jrebel doesn't invoke the constructor (again) when >>> replacing the code. Moving the code to onInitialize() might enable the >>> jrebel plugin to call that method when it modifies a component class. >>> This won't work because you typically then get: >>> >>> java.lang.IllegalArgumentException: A child with id 'counter' >>> already exists: >>> >>> Now we could ask folks to use addOrReplace() instead of add(), or we >>> could relax the multi add restriction to alleviate this problem. >>> >>> I wouldn't be against relaxing add() and deprecating addOrReplace(). >>> >>> Now calling onInitialize again on a constructed component might open >>> up another can of worms. >>> >>> Is this something worth pursuing? Or should we just write an article >>> with how to do jrebel no-redeploy wicket coding? >>> >>> Martijn >>> >> >