Hi,

Iím using Spring Form Tags together with custom property editors defined in a controller to handle forms. Now, I would also like to use the same custom property editors to output the bean data in tables and lists outside of forms.
What would be the best practice to do that?

I though about creating an output tag that has the same functionality as an form:input tag but outputs the content of the value attribute directly.
Actually Iím already working on it, but Iím stuck with some architectural problems. The current version of the tag (created mainly by using copy&paste from different super classes of the InputTag class) looks like this:

Code:
public class OutputTag extends RequestContextAwareTag
{
    /**
     * The {@link BindStatus} of this tag.
     */
    private BindStatus bindStatus;
    private String path;

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.web.servlet.tags.RequestContextAwareTag#doStartTagInternal()
     */
    @Override
    protected int doStartTagInternal() throws Exception
    {
        this.pageContext.getOut().write(getDisplayString(getBoundValue(), getPropertyEditor(), false));
        return SKIP_BODY;
    }
    
    /* (non-Javadoc)
     * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
     */
    @Override
    public int doEndTag() throws JspException
    {
        this.bindStatus = null;
        return super.doEndTag();
    }

    
    
    /**
     * Set the property path from the {@link FormTag#setModelAttribute form object}. May be a runtime expression.
     */
    public void setPath(String path)
    {
        this.path = path;
    }

    /**
     * Get the {@link #evaluate resolved} property path for the {@link FormTag#setModelAttribute form object}.
     */
    protected final String getPath() throws JspException
    {
        return path;
    }

    /**
     * Get the {@link BindStatus} for this tag.
     */
    protected BindStatus getBindStatus() throws JspException
    {
        if (this.bindStatus == null)
        {
            // HTML escaping in tags is performed by the ValueFormatter class.
            String pathToUse = getPath();
            if (pathToUse.endsWith(PropertyAccessor.NESTED_PROPERTY_SEPARATOR))
            {
                pathToUse = pathToUse.substring(0, pathToUse.length() - 1);
            }
            this.bindStatus = new BindStatus(getRequestContext(), pathToUse, false);
        }
        return this.bindStatus;
    }

    /**
     * Get the bound value.
     * 
     * @see #getBindStatus()
     */
    protected final Object getBoundValue() throws JspException
    {
        return getBindStatus().getValue();
    }

    /**
     * Get the {@link PropertyEditor}, if any, in use for value bound to this tag.
     */
    protected PropertyEditor getPropertyEditor() throws JspException
    {
        return getBindStatus().getEditor();
    }

    /**
     * Exposes the {@link PropertyEditor} for {@link EditorAwareTag}.
     * <p>
     * Use {@link #getPropertyEditor()} for internal rendering purposes.
     */
    public final PropertyEditor getEditor() throws JspException
    {
        return getPropertyEditor();
    }

    /**
     * Build the display value of the supplied <code>Object</code>, HTML escaped as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
     * 
     * @see #getDisplayString(Object, java.beans.PropertyEditor, boolean)
     */
    public static String getDisplayString(Object value, boolean htmlEscape)
    {
        String displayValue = ObjectUtils.getDisplayString(value);
        return (htmlEscape ? HtmlUtils.htmlEscape(displayValue) : displayValue);
    }

    /**
     * Build the display value of the supplied <code>Object</code>, HTML escaped as required. If the supplied value is not a {@link String} and the supplied {@link PropertyEditor}
     * is not null then the {@link PropertyEditor} is used to obtain the display value.
     * 
     * @see #getDisplayString(Object, boolean)
     */
    public static String getDisplayString(Object value, PropertyEditor propertyEditor, boolean htmlEscape)
    {
        
        if (propertyEditor != null && !(value instanceof String))
        {
            try
            {
                propertyEditor.setValue(value);
                return getDisplayString(propertyEditor.getAsText(), htmlEscape);
            }
            catch (Throwable ex)
            {
                // The PropertyEditor might not support this value... pass through.
                return getDisplayString(value, htmlEscape);
            }
        }
        else
        {
            return getDisplayString(value, htmlEscape);
        }
    }

}

In a forEach loop I can use something like:

Code:
<tag:out path=Ē<beanName>.<propertyName>Ē />
and itís working. But the output tag doesnít use the property editors that are defined in the controller. At this moment the standard output generated by the toString() method is used.

I think there are two reasons for this. Firstly, Spring doesnít call the @InitBinder annotated method until the @RequestMapping annotated method does require some @ModelAttribute annotated parameter. Secondly, in the constructor of the BindStatus class, there is no logic to find a suitable property editor if there is no BindingResult object in the request context.

So, how can it be solved? What would be a best-practice to reuse the property editor configuration defined in the controller for bean data output?

Regards,
Adrian.