I've been playing around with managed properties recently and noticed some behavior that I did not quite expect when using map-entries against a Map property on my managed bean.

If I create a set of map values like this, everything works fine and I get my values in a map in my managed bean.

        ....
        <managed-property>
            <property-name>someMapping</property-name>
            <map-entries>   
                <map-entry>
                    <key>key1</key>
                    <value>value1</value>
                </map-entry>
                <map-entry>
                    <key>key2</key>
                    <value>value2</value>
                </map-entry>
             </map-entries>
         </managed-property>
         ....

However, I decided I wanted my values to be sorted, so I added in a line to specify the exact type of Map (TreeMap) class I wanted to be created for me:

        ....
        <managed-property>
            <property-name>someMapping</property-name>
            <property-class>java.util.TreeMap</property-class>
            <map-entries>   
                <map-entry>
                    <key>key1</key>
                    <value>value1</value>
                </map-entry>
                <map-entry>
                    <key>key2</key>
                    <value>value2</value>
                </map-entry>
             </map-entries>
         </managed-property>
         ....

When MyFaces attempt to create my bean, it blows up trying to coerce a HashMap to a TreeMap (see stack trace at end of email). Looking through the code, I can see that in ManagedBeanBuilder.initializeProperties the value is being created as a HashMap. To me, this looks like a bug... the value should be created as a HashMap only if the property's Class value is not set (and if it's type is set to a non-Map, an class-cast exception would be thrown)

something like:

                case ManagedProperty.TYPE_MAP:
                    if (property.getPropertyClass != null) {
                        Class mapClass = ClassUtils.simpleJavaTypeToClass(property.getPropertyClass());
                        value = mapClass.newInstance();
                    } else {
                          value = new HashMap();
                    }

                    initializeMap(facesContext, property.getMapEntries(), (Map) value);
                    break;

etc... etc... same would probably go for Lists as well.

Any thoughts on this? I'm not an expert of the JSF spec - is there any mention about if its legal to combine map-entries with a specific property class in your faces config xml?


--- Stack Trace Below ------------

Caused by: javax.faces.FacesException: Cannot coerce java.util.HashMap to java.util.TreeMap
        at org.apache.myfaces.util.ClassUtils.convertToType(ClassUtils.java:321)
        at org.apache.myfaces.config.ManagedBeanBuilder.initializeProperties(ManagedBeanBuilder.java:150)
        at org.apache.myfaces.config.ManagedBeanBuilder.buildManagedBean(ManagedBeanBuilder.java:63)
        at org.apache.myfaces.el.VariableResolverImpl.resolveVariable(VariableResolverImpl.java:328)
        at org.apache.myfaces.el.ValueBindingImpl$ELVariableResolver.resolveVariable(ValueBindingImpl.java:637)
        at org.apache.commons.el.NamedValue.evaluate(NamedValue.java:124)
        at org.apache.commons.el.ComplexValue.evaluate(ComplexValue.java:140)
        at org.apache.myfaces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:441)
        ... 42 more
Caused by: javax.servlet.jsp.el.ELException: Attempt to coerce a value of type "java.util.HashMap" to type "java.util.TreeMap"
        at org.apache.commons.el.Logger.logError(Logger.java:481)
        at org.apache.commons.el.Logger.logError(Logger.java:498)
        at org.apache.commons.el.Logger.logError(Logger.java:566)
        at org.apache.commons.el.Coercions.coerceToObject(Coercions.java:799)
        at org.apache.commons.el.Coercions.coerce(Coercions.java:343)
        at org.apache.myfaces.util.ClassUtils.convertToType(ClassUtils.java:314)
        ... 49 more



           

Reply via email to