I have lots of beans and all use LocalDate and LocalDateTime. The DateTextField in Wicket and all other widgets (like the DatePicker) only work on java.util.Date. Is there any way to inject a converter into Wicket 7 so that it uses LocalDate or LocalDateTime?
The beans look like this:
public class SomeBean {
Long id = null;
LocalDate since = null;
// plus getters and setters
}
A Wicket form currently uses a CompoundPropertyModel
CompoundPropertyModel<SomeBean> model = new CompundPropertyModel<>( bean );
You can wrap your LocalDate
and etc. models in a IModel<java.util.Date>
, e.g.
public static class LocalDateModel implements IModel<java.util.Date> {
private IModel<LocalDate> localDateModel;
public LocalDateModel(IModel<LocalDate> localDateModel){
this.localDateModel = localDateModel;
}
@Override
public Date getObject() {
return convertLocalDateToUtilDateSomehow(localDateModel.getObject());
}
@Override
public void setObject(Date object) {
localDateModel.setObject(convertUtilDateToLocalDateSomehow(object));
}
@Override
public void detach() {
localDateModel.detach();
}
}
If you then feed models like this into the form components you want to use it should work just fine.
If you want your CompoundPropertyModel
to automatically provide such wrapping models, you need to extend it and override it's CompoundPropertyModel#wrapOnInheritance(Component component)
method to infer that a wrapping model is needed. Something like
@Override
public <C> IWrapModel<C> wrapOnInheritance(Component component)
{
IWrapModel<C> actualModel = super.wrapOnInheritance(component);
if (actualModel.getObject() instanceOf LocalDate) {
return new LocalDateModelButAlsoWrapping(actualModel);
} else {
return actualModel;
}
}
Where LocalDateModelButAlsoWrapping
is unsurprisingly just an extension of LocalDateModel
example above but which also implements IWrapModel<T>
.
If you use this extension instead of your regular CompoundPropertyModel
it would detect when fields are LocalDate
and provide models to components (like your DateTextField
) that are wrapped to look like java.util.Date
models.
The code snippet I gave you is rather dirty though (you should probably not get the model object to infer its type) as I have only provided it to illustrate the general mechanism, so I suggest you devise your own way to infer the type of object expected (e.g. you can check if the Component
argument is a DateTextField
), but this is the general direction of the solution that I can imagine.
You can register your own converters:
https://ci.apache.org/projects/wicket/guide/7.x/guide/forms2.html#forms2_3
@Override
protected IConverterLocator newConverterLocator() {
ConverterLocator defaultLocator = new ConverterLocator();
defaultLocator.set(Pattern.class, new RegExpPatternConverter());
return defaultLocator;
}
Related: https://issues.apache.org/jira/browse/WICKET-6200
You can simply backport the converter classes from Wicket 8. You'll find these attached to this commit: https://issues.apache.org/jira/browse/WICKET-6200 (AbstractJavaTimeConverter and whatever subclasses you need for LocalDate, LocalDateTime, LocalTime, etc.)
Of course, that will not help with a DateTextField, because that has the Date type parameter hardcoded. For such, you can either create your own subclasses using the above converters, or use regular Label and TextField, with converters registered globally, as shown below:
@Override
protected IConverterLocator newConverterLocator() {
ConverterLocator converterLocator = new ConverterLocator();
converterLocator.set(LocalDateTime.class, new LocalDateTimeConverter());
converterLocator.set(LocalDate.class, new LocalDateConverter());
converterLocator.set(LocalTime.class, new LocalDateConverter());
return converterLocator;
}