Some months ago there were discussion about how to use immutable value objects in wicket. See: http://thread.gmane.org/gmane.comp.java.wicket.user/12887/focus=12887
The conclusion was that wicket does not support well such a case currently (http://article.gmane.org/gmane.comp.java.wicket.user/12911). However, I think there may be pretty easy way to solve the issue. Provide a FormComponent which can use associated markup file, just like a Panel: public abstract class CompoundFormComponent extends FormComponent { private boolean wasOpenCloseTag = false; public CompoundFormComponent(String id) { super(id); } public CompoundFormComponent(String id, IModel model) { super(id, model); } @Override public abstract void updateModel(); @Override protected void onComponentTag(final ComponentTag tag) { if (tag.isOpenClose()) { this.wasOpenCloseTag = true; // Convert <span wicket:id="myPanel" /> into // <span wicket:id="myPanel">...</span> tag.setType(XmlTag.OPEN); } super.onComponentTag(tag); } @Override protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) { // Render the associated markup renderAssociatedMarkup("panel", "Markup for a panel component has to contain part '<wicket:panel>'"); if (this.wasOpenCloseTag == false) { // Skip any raw markup in the body markupStream.skipRawMarkup(); } } } Note, the methods onComponentTag and onComponentTagBody are copy pasted from Panel. The method updateModel() is made abstract, this is the place where the immutable value object is created from convertedInputs of FormComponents. Now, the IntegerRangeField (see the original thread) can be written simply as: IntegerRangeField.java: public class IntegerRangeField extends CompoundFormComponent { private final TextField minimum; private final TextField maximum; public IntegerRangeField(Form parent, String id, IModel/*<IntegerRange>*/model) { super(id, model); minimum = new RequiredTextField("minimum", new Model(defaultMinimumValue()), Integer.class); maximum = new RequiredTextField("maximum", new Model(defaultMaximumValue()), Integer.class); add(minimum); add(maximum); parent.add(new Validator(this)); } @Override public void updateModel() { setModelObject(new IntegerRange( (Integer) minimum.getConvertedInput(), (Integer) maximum.getConvertedInput())); } private Integer defaultMinimumValue() { if (rangeValue() == null) { return null; } return rangeValue().getMinimum(); } private Integer defaultMaximumValue() { if (rangeValue() == null) { return null; } return rangeValue().getMaximum(); } private IntegerRange rangeValue() { return (IntegerRange) getModelObject(); } public static class Validator extends AbstractFormValidator { ... } } IntegerRangeField.html: <?xml version="1.0" encoding="utf-8"?> <wicket:panel> <table cellpadding="0" cellspacing="0" border="0"> <tr> <td> <input wicket:id="minimum" type="text" class="text numeric" size="8" /> </td> <td> - </td> <td> <input wicket:id="maximum" type="text" class="text numeric" size="8" /> </td> </tr> </table> </wicket:panel> I tried this with other immutables too, like DateRanges etc. and the implementation was always straight forward. The original implementations were much more complex and required deep knowledge of wicket's form processing. It would be great to see something like this in core since the abstract CompoundFormComponent contains copy pasted code from Panel. Joni ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Wicket-user mailing list Wicket-user@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/wicket-user