BindStatus hides real field value with custom editors
Hello, I'm using the spring MVC + Velocity + Hibernate combo. I recently changed over the new way of making forms using the BindStatus object. I am generating my selection lists with this macro:
Code:
#macro( selectEntity $path $entities )
#springBind($path)
<!-- status.value is $status.value.class $status.value -->
<select name="${status.expression}">
#foreach($entity in $entities)
#if($status.value && $status.value == $entity)
#set( $sel = 'selected="true"' )
#else
#set( $sel = "" )
#end
<option value="${entity.id}" $sel>${entity.name}</option>
#end
</select>
#end
The first time I enter the editing form, I construct the model object like this:
Code:
public Map getModel(Object command) {
return new BindException(command, "this").getModel();
}
When the user submits the form, I update the Object in question and create the model using:
Code:
protected Map bindAndValidate(ServletRequest request, Object command) throws ServletException {
ServletRequestDataBinder binder = new ServletRequestDataBinder(command, "this");
new GameslaveBindInitializer(getStorage()).initBinder(request, binder);
binder.bind(request);
return binder.getErrors().getModel();
}
The GameslaveBindInitializer adds a bunch of custom property editors which looks up object Ids in the database for each type I store in the database. (side note: I wonder if this could be automated based on hibernate metadata?)
Now for the problem: the first time I construct the object and render the template (using getModel()), $status.value is correctly set to a gameslave.dnd35.db.* instance. However, in a subsequent edit (using bindAndValidate()), $status.value is a string, thus screwing up the form logic.
Taking a look at BindException we easily find a culprit:
Code:
public Object getFieldValue(String field) {
FieldError fe = getFieldError(field);
String fixedField = fixedField(field);
// use rejected value in case of error, current bean property value else
Object value = (fe != null) ? fe.getRejectedValue() : getBeanWrapper().getPropertyValue(fixedField);
// apply custom editor, but not on binding failures like type mismatches
if (fe == null || !fe.isBindingFailure()) {
PropertyEditor customEditor = getCustomEditor(fixedField);
if (customEditor != null) {
customEditor.setValue(value);
return customEditor.getAsText();
}
}
return value;
}
Note how BindException will always return a String instance for fields with a custom editor; fields without custom editors, however, will be returned as an object. I can guess at the reasoning behind this but it is inconvenient for me.
I think BindStatus should have an accessor that returns the original object instead of a translated string even when there is a property editor.
As a workaround, I can check whether $status.editor is not null, and if so use $status.editor.value instead of $status.value (I think - I'll try once I'm done this post).