Announcement Announcement Module
Collapse
No announcement yet.
BindStatus hides real field value with custom editors Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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="$&#123;status.expression&#125;">
    		#foreach&#40;$entity in $entities&#41;
    			#if&#40;$status.value && $status.value == $entity&#41;
    				#set&#40; $sel = 'selected="true"' &#41;
    			#else
    				#set&#40; $sel = "" &#41;
    			#end
    			<option value="$&#123;entity.id&#125;" $sel>$&#123;entity.name&#125;</option>
    		#end
    	</select>
    #end
    The first time I enter the editing form, I construct the model object like this:

    Code:
    	public Map getModel&#40;Object command&#41; &#123;
    		return new BindException&#40;command, "this"&#41;.getModel&#40;&#41;;
    	&#125;
    When the user submits the form, I update the Object in question and create the model using:

    Code:
    	protected Map bindAndValidate&#40;ServletRequest request, Object command&#41; throws ServletException &#123;
    		ServletRequestDataBinder binder = new ServletRequestDataBinder&#40;command, "this"&#41;;
    		new GameslaveBindInitializer&#40;getStorage&#40;&#41;&#41;.initBinder&#40;request, binder&#41;;
    		binder.bind&#40;request&#41;;
    		return binder.getErrors&#40;&#41;.getModel&#40;&#41;;
    	&#125;
    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&#40;String field&#41; &#123;
    		FieldError fe = getFieldError&#40;field&#41;;
    		String fixedField = fixedField&#40;field&#41;;
    		// use rejected value in case of error, current bean property value else
    		Object value = &#40;fe != null&#41; ? fe.getRejectedValue&#40;&#41; &#58; getBeanWrapper&#40;&#41;.getPropertyValue&#40;fixedField&#41;;
    		// apply custom editor, but not on binding failures like type mismatches
    		if &#40;fe == null || !fe.isBindingFailure&#40;&#41;&#41; &#123;
    			PropertyEditor customEditor = getCustomEditor&#40;fixedField&#41;;
    			if &#40;customEditor != null&#41; &#123;
    				customEditor.setValue&#40;value&#41;;
    				return customEditor.getAsText&#40;&#41;;
    			&#125;
    		&#125;
    		return value;
    	&#125;
    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).
Working...
X