f:selectItem's key and value inverted when feeding from a map

comandante N picture comandante N · Mar 27, 2012 · Viewed 9.5k times · Source

In JSF's tag, if you feed it using a Map<Key, Value>

<h:selectOneMenu value="#{bean.integerProperty}">
  <f:selectItems value="#{bean.mapProperty}"/>
</h:selectOneMenu>

The resulting HTML will be the inverse of what one would expect

<select>
  <option selected="selected" value="MapValue1">MapKey1</option>
  <option value="MapValue2">MapKey2</option>
  <option value="MapValue3">MapKey3</option>
</select>

In the sense that the map's value will be set in the option's value attribute and the key will be set in its label.

I found this JIRA JIRA 1808 where the implications of having to write wrong maps are explained (uniqueness, mostly), but don't quite understand why correcting this would be

'disruptive and backwards incompatible'.

Does this come from previous versions of JSF? If so, does anybody know if there's a reason for it to be like this?

Just curious about if there's an explanation not to fix this.

Answer

BalusC picture BalusC · Mar 27, 2012

The initial reasoning is after all rather simple: dropdown labels have a greater precedence of to be unique than dropdown values. A dropdown with two same labels would be more a "wtf?" for the enduser than a dropdown with two same values. Map keys ensure uniqueness. I have indeed ever reported the technical unintuitiveness in the issue report which you linked yourself. However, it's a WONTFIX. If it would be changed in JSF 2.2, it wouldn't be backwards compatible anymore with JSF 2.0 / 2.1.

If your environment supports EL 2.2 (Tomcat 7, Glassfish 3, etc), you can easily swap it as follows:

<h:selectOneMenu value="#{bean.integerProperty}">
  <f:selectItems value="#{bean.mapProperty.entrySet()}" var="entry" 
     itemValue="#{entry.key}" itemLabel="#{entry.value}" />
</h:selectOneMenu>

See also: