この問題は列挙型には特に関係ありません。、などList
の JSF に組み込みコンバーターがある他のタイプでも同じ問題が発生します。List<Integer>
List<Double>
問題は、EL が実行時に動作し、ジェネリック型情報が実行時に失われることです。したがって、本質的に、JSF/EL は のパラメーター化された型について何も認識せず、明示的に指定されていない限りList
、デフォルトは になります。理論的には、 の助けを借りて厄介なリフレクション ハックを使用することは可能でしたが、JSF/EL 開発者にはこれを行わない理由があるかもしれません。String
Converter
ParameterizedType#getActualTypeArguments()
これには、コンバーターを明示的に定義する必要があります。JSF にはすでにビルトインが付属しているためEnumConverter
(実行時に列挙型を指定する必要があるため、この特定のケースではスタンドアロンでは使用できません)、次のように拡張できます。
package com.example;
import javax.faces.convert.EnumConverter;
import javax.faces.convert.FacesConverter;
@FacesConverter(value="securityRoleConverter")
public class SecurityRoleConverter extends EnumConverter {
public SecurityRoleConverter() {
super(SecurityRole.class);
}
}
そして、次のように使用します。
<h:selectManyCheckbox value="#{userController.roles}" converter="securityRoleConverter">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
また
<h:selectManyCheckbox value="#{userController.roles}">
<f:converter converterId="securityRoleConverter" />
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
もう少し一般的な (そしてハックな) 解決策は、列挙型をコンポーネント属性として格納することです。
package com.example;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
@FacesConverter(value="genericEnumConverter")
public class GenericEnumConverter implements Converter {
private static final String ATTRIBUTE_ENUM_TYPE = "GenericEnumConverter.enumType";
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value instanceof Enum) {
component.getAttributes().put(ATTRIBUTE_ENUM_TYPE, value.getClass());
return ((Enum<?>) value).name();
} else {
throw new ConverterException(new FacesMessage("Value is not an enum: " + value.getClass()));
}
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Class<Enum> enumType = (Class<Enum>) component.getAttributes().get(ATTRIBUTE_ENUM_TYPE);
try {
return Enum.valueOf(enumType, value);
} catch (IllegalArgumentException e) {
throw new ConverterException(new FacesMessage("Value is not an enum of type: " + enumType));
}
}
}
List<Enum>
コンバーター IDを使用するあらゆる種類で使用できますgenericEnumConverter
。List<Double>
、などについては、組み込みのコンバーターなどList<Integer>
を使用していたでしょう。ちなみに、組み込みの Enum コンバーターは、ビュー側からターゲットの列挙型 (a) を指定できないため、不適切です。JSF ユーティリティ ライブラリOmniFacesは、まさにこのコンバータをそのまま提供します。javax.faces.Double
javax.faces.Integer
Class<Enum>
通常のEnum
プロパティの場合、ビルトインEnumConverter
で十分であることに注意してください。JSF は、適切なターゲット列挙型を使用して自動的にインスタンス化します。