QeelwaEtech / omnifaces

Automatically exported from code.google.com/p/omnifaces
0 stars 1 forks source link

Base class for Converter (UIInput) that checks for changed value #182

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
While using primefaces autocomplete with an list-converter filled by the 
autocomplete `filter` method I ran into the issue that if the User does not 
interacts with the component the Converter will still be called which resulted 
in a validation error since converter returned null. (No `filter` call meant 
empty list in converter..)

It took much time until i thought my converter was the problem, since 
straightforward I thought no conversion would apply to unchanged values.

My first approach to fix this issue was a remote/database fallback converter to 
fix the empty list problem. 
Not really satisfied with the complete situation about the conversion and the 
performance impact of either searching or retrieving remote or from database I 
now check if the value was changed with following code.

If String representation does not changes how should Object change since same 
converter is used for de- and encoding.

public Object getAsObject(final FacesContext context, final UIComponent 
component, final String value)
{
    if (StringUtils.isBlank(value))
        return null;

    if (component instanceof UIInput)
    {
        final Object oldObjValue = ((UIInput) component).getValue();
        final String oldValue = this.getAsString(context, component, oldObjValue);
        // equal check
        if (value.equals(oldValue))
            return oldObjValue;
    }

    // do conversion here if value has changed
}

So if you think this is a good idea this maybe usefull for others.

Original issue reported on code.google.com by releases...@googlemail.com on 31 May 2013 at 12:38

GoogleCodeExporter commented 9 years ago
Maybe a construct like following which should support all UIComponent classes 
where the default request value can be retrieved and compared, just know of 
UIInput yet.

/**
 * Abstract Jsf Converter used for UIComponent's such as {@link UIInput} which
 * hold the default request value where the conversion method
 * {@link #getAsObjectImpl(FacesContext, UIComponent, String)} will only be
 * called if the value has changed.
 */
public abstract class ValueChangedConverterImpl implements ValueChangedConverter
{
    @Override
    public Object getAsObject(final FacesContext context, final UIComponent component, final String value)
    {
        if (component instanceof UIInput)
        {
            final Object oldObjValue = ((UIInput) component).getValue();
            final String oldValue = this.getAsString(context, component, oldObjValue);
            if (oldValue.equals(value))
                return oldObjValue;
        }

        return this.getAsObjectImpl(context, component, value);
    }
}

/**
 * Jsf Converter interface for UIComponent's such as {@link UIInput} which hold
 * the default request value where the conversion method
 * {@link #getAsObjectImpl(FacesContext, UIComponent, String)} should only be
 * called if the value has changed.
 */
public interface ValueChangedConverter extends Converter
{
    /**
     * Wrapper method for
     * {@link #getAsObject(FacesContext, UIComponent, String)}.
     * 
     * @see #getAsObject(FacesContext, UIComponent, String)
     */
    public Object getAsObjectImpl(final FacesContext context, final UIComponent component, final String value);
}

Original comment by releases...@googlemail.com on 1 Jun 2013 at 12:45

GoogleCodeExporter commented 9 years ago
Notes: 
- Null check on component before instanceof check.
- Check value being null at beginning and use 'value.equals(oldValue)'

if (value == null)
    return null;

if (component != null && component instanceof UIInput)
{
    final Object oldObjValue = ((UIInput) component).getValue();
    final String oldValue = this.getAsString(context, component, oldObjValue);
    if (value.equals(oldValue))
        return oldObjValue;
}

Original comment by releases...@googlemail.com on 1 Jun 2013 at 12:53

GoogleCodeExporter commented 9 years ago
Makes sense.

Nullcheck before instanceof is by the way unnecessary. Instanceof always 
returns false on null.

Original comment by balusc on 6 Jul 2013 at 3:02

GoogleCodeExporter commented 9 years ago
Ah did not knew this. Yeah any comparison on null should return null.

Still I think this should be built-in in jsf. Maybe I file an issue later.

Original comment by releases...@googlemail.com on 6 Jul 2013 at 3:07

GoogleCodeExporter commented 9 years ago
Added: 
https://code.google.com/p/omnifaces/source/detail?r=f581da0a1cfa93ecbba1047d0c01
9100b5814d19

It's available in today's latest snapshot: 
https://oss.sonatype.org/content/repositories/snapshots/org/omnifaces/omnifaces/
1.6-SNAPSHOT/

Original comment by balusc on 6 Jul 2013 at 4:09

GoogleCodeExporter commented 9 years ago
Thanks again, updated my implementing converters to use your implementation. 
Always happy for less code in my big project.

Original comment by releases...@googlemail.com on 1 Aug 2013 at 3:47