Hi,
For Wicket In Action in converted an example from a ListView to a
RepeatingView. This example has to function in a form, so I set the
'ReuseIfModelsEqualStrategy'. Overriding hashCode (and equals) on the
model however results in quite a bit of code bloat, while my hunch is
that comparing the model values is actually a pretty common use case.
So, in my quest to cut down a few lines, I would basically have two
choices: implement a reuse strategy that does this, or implement a
model wrapper that implements hashCode and equals in a generic
fashion. I choose the latter, and would like to hear your opinions
whether this is something we could add to the project (I think the use
case for it should be common enough, especially since I would mention
it in the book), or whether you would prefer to have a reuse strategy
that does this.
I'd really like to see one of these in the project, as otherwise I
would have to either include the equals/ hashCode implementation
inline, which bloats the example, or I would have to give the code in
the book as people will want to play with it. Both would suck.
Cheers,
Eelco
My implementation (no javadocs):
package wicket.in.action.common;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.lang.Objects;
public final class EqualsDecorator {
private EqualsDecorator() {
}
public static IModel decorate(final IModel model) {
return (IModel) Proxy.newProxyInstance(model.getClass()
.getClassLoader(), model.getClass().getInterfaces(),
new Decorator(model));
}
private static class Decorator implements InvocationHandler,
Serializable {
private final IModel model;
Decorator(IModel model) {
this.model = model;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (methodName.equals("equals")) {
if (args[0] instanceof IModel) {
return Objects.equal(model.getObject(), ((IModel) args[0])
.getObject());
}
} else if (methodName.equals("hashCode")) {
Object val = model.getObject();
return 37 + (val != null ? val.hashCode() : 0);
} else if (methodName.equals("writeReplace")) {
return new SerializableReplacement(model);
}
return method.invoke(model, args);
}
}
private static class SerializableReplacement implements
Serializable {
private final IModel model;
SerializableReplacement(IModel model) {
this.model = model;
}
private Object readResolve() throws ObjectStreamException {
return decorate(model);
}
}
}