I want to use enum values in a <h:selectManyCheckbox>. The checkboxes get populated correctly, however, when selecting some values and submitting them, their runtime type is String, and not enum. My code:
<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
UserController class (SecurityRole is an enum type):
public SelectItem[] getRolesSelectMany() {
SelectItem[] items = new SelectItem[SecurityRole.values().length];
int i = 0;
for (SecurityRole role : SecurityRole.values()) {
items[i++] = new SelectItem(role, role.toString());
}
return items;
}
public List<SecurityRole> getRoles() {
getCurrent().getRoles();
}
public void setRoles(List<SecurityRole> roles) {
getCurrent().setRoles(roles);
}
When JSF calls the setRoles method, it contains a list of type String, and not the enum type. Any ideas? Thanks!
This problem is not specifically related to enums. You would have the same problem with other
Listtypes for which JSF has builtin converters, e.g.List<Integer>,List<Double>, etcetera.The problem is that EL operates runtime and that generic type information is lost during runtime. So in essence, JSF/EL doesn’t know anything about the parameterized type of the
Listand defaults toStringunless otherwise specified by an explicitConverter. In theory, it would have been possible using nasty reflection hacks with help ofParameterizedType#getActualTypeArguments(), but the JSF/EL developers may have their reasons for not doing this.You really need to explicitly define a converter for this. Since JSF already ships with a builtin
EnumConverter(which isn’t useable standalone in this particular case because you have to specify the enum type during runtime), you could just extend it as follows:And use it as follows:
or
A bit more generic (and hacky) solution would be to storing the enum type as component attribute.
It’s useable on all kinds of
List<Enum>using converter IDgenericEnumConverter. ForList<Double>,List<Integer>, etc one would have used the builtin convertersjavax.faces.Double,javax.faces.Integerand so on. The builtin Enum converter is by the way unsuitable due to the inability to specify the target enum type (aClass<Enum>) from the view side on. The JSF utility library OmniFaces offers exactly this converter out the box.Note that for a normal
Enumproperty, the builtinEnumConverteralready suffices. JSF will instantiate it automagically with the right target enum type.