InputRenderer ignores any defined enum custom converter

UI Components for JSF
Post Reply
dvankeer
Posts: 10
Joined: 02 Aug 2011, 16:15

28 Oct 2011, 15:40

When trying to find out why my custom enum converter is not trigger by PrimeFaces, i decided to look into the source code:

Code snippet from 'org.primefaces.renderkit.InputRenderer' lines 78-87

Code: Select all

 if(object instanceof SelectItem) {
                                selectItems.add((SelectItem) object);
                            }
                            else if(object instanceof Enum) {
                                Enum e = (Enum) object;
                                selectItems.add(new SelectItem(itemValue == null ? e.name() : itemValue, itemLabel == null ? e.name() : itemLabel, description, disabled, escaped, noSelectionOption));
                            }
                            else{
                                selectItems.add(new SelectItem(itemValue == null ? object : itemValue, itemLabel == null ? object.toString() : itemLabel, description, disabled, escaped, noSelectionOption));
                            }
So if i look at this correctly, then for each Enum type any defined converter is ignored and the name of the enum is used instead?

PS: Code snippet is from google code trunk from today. Older version is basically the same logic what this issue is concerned.
Primefaces: 3.5.0 - JSF implementation: Mojarra 2.1.7 - Server: jBoss AS 7.1.1

dvankeer
Posts: 10
Joined: 02 Aug 2011, 16:15

28 Oct 2011, 21:11

Ok. have been digging a bit further on this subject and got things working by hacking the current code a bit. But i wonder if their is more to this then i first thought.

Let see if i can relay my findings a bit. I have special enumerations which relate to database stored values, each enumeration is tagged with a interface named 'DatabaseEnum'.

For these enumeration i have created a special custom converter called DatabaseEnumConverter, which has a FacesConverter annotation attached to it.

Code: Select all

@FacesConverter(forClass = DatabaseEnum.class)
public class DatabaseEnumConverter implements Converter, PartialStateHolder {
The InputRenderer class seems to happily ignore this class, since it basically says to itself.. Enum, ok i know how to handle this myself. But in my case the values are stored in the so called FlashScope and when retrieving them from this scope the enums are just given back as String values.... Which is not what i expect, i expected a enum back ;-)

To fix this issue i added a few lines of code the the InputRenderer mentioned above (Based on SVN revision 5798):

Code: Select all

if(object instanceof SelectItem) {
    selectItems.add((SelectItem) object);
}
else if(object instanceof Enum) {
    Enum e = (Enum) object;

    // Check if a converter is available, use it if so and register it to the component for correct decoding as well.
    Converter converter = context.getApplication().createConverter(object.getClass());
    if (converter != null) {
        component.setConverter(converter);
        itemValue = getOptionAsString(context, component, converter, object);
    }

    selectItems.add(new SelectItem(itemValue == null ? e.name() : itemValue, itemLabel == null ? e.name() : itemLabel, description, disabled, escaped, noSelectionOption));
}
else{
    selectItems.add(new SelectItem(itemValue == null ? object : itemValue, itemLabel == null ? object.toString() : itemLabel, description, disabled, escaped, noSelectionOption));
}
Now the converter is taking into account and the values in the flash scope, are the actual enumeration values i expected. But this makes me wonder, are more converters ignored? Especially worried about the ones which are defined with a @FacesConverter(forClass=....) annotation?
Primefaces: 3.5.0 - JSF implementation: Mojarra 2.1.7 - Server: jBoss AS 7.1.1

dvankeer
Posts: 10
Joined: 02 Aug 2011, 16:15

30 Oct 2011, 16:49

Ok, have been going through the code some more to understand the issue a bit more. It seems that during the encode of the select items (used in all Select*Renderer class) a check is done to retrieve the converter based on the context and the component itself:

Code from org.primefaces.renderkit.InputRenderer (line 111-128)

Code: Select all

protected Converter getConverter(FacesContext context, UIInput component) {
    Converter converter = component.getConverter();

    if(converter != null) {
        return converter;
    } else {
       ValueExpression ve = component.getValueExpression("value");

       if(ve != null) {
           Class<?> valueType = ve.getType(context.getELContext());

           if(valueType != null)
                return context.getApplication().createConverter(valueType);
        }
    }

    return null;
}
This works great if the valueExpression is linked to a actual existing bean or something else. But this fails to resolve anything if a expression is used which access the FlashScope in JSF 2.0 ( http://javaserverfaces.java.net/nonav/d ... Flash.html ).

Since i use the flash scope to store temp object (to use, for example in the creation of a new bean, based on the stored data in flash scope). I now wonder if i need to put a placeholder object in the flash scope in advance? This so the the valueType can be determined correctly?

Moral of the story i guess: either attach a converter in the JSF page or make the value type expression resolve to the type you want. Since the supplied select items are not used for assigning a converter to the component.
Primefaces: 3.5.0 - JSF implementation: Mojarra 2.1.7 - Server: jBoss AS 7.1.1

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 38 guests