質問

enum値を使用したい <h:selectManyCheckbox>. 。チェックボックスには正しく値が入力されますが、いくつかの値を選択して送信すると、そのランタイム タイプは次のようになります。 String, 、列挙型ではありません。私のコード:

<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
     <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

UserController クラス (SecurityRole は列挙型):

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);
}

JSF が setRoles メソッドを呼び出すと、それには enum 型ではなく String 型のリストが含まれます。何か案は?ありがとう!

役に立ちましたか?

解決

この問題は特に列挙型に関連するものではありません。他の人でも同じ問題が発生するでしょう List JSF にコンバーターが組み込まれている型 (例: List<Integer>, List<Double>, 、など。

問題は、EL が実行時に動作し、ジェネリック型情報が実行時に失われることです。したがって、本質的に、JSF/EL はパラメータ化された型について何も知りません。 List そしてデフォルトは String 明示的に指定されていない限り、 Converter. 。理論的には、次の助けを借りて厄介なリフレクション ハックを使用することは可能でした。 ParameterizedType#getActualTypeArguments(), しかし、JSF/EL 開発者にはこれを行わない理由があるかもしれません。

これにはコンバータを明示的に定義する必要があります。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>, など、組み込みコンバータを使用することになるでしょう。 javax.faces.Double, javax.faces.Integer 等々。ちなみに、組み込みの Enum コンバータは、ターゲットの enum 型を指定できないため、適切ではありません ( Class<Enum>)ビュー側から。JSFユーティリティライブラリ オムニフェイス まさにこのコンバーターを提供します 箱から出して.

通常の場合は、 Enum プロパティ、ビルトイン EnumConverter もう十分です。JSF は、適切なターゲット列挙型を使用して自動的にそれをインスタンス化します。

他のヒント

いくつかの場合にはの一覧するはちょうど同様に、アレイの SomeType [] をすることができ、この場合、明示的な変換は必要とされない。

ジェネリック消去古いものを壊すことなく、言語にジェネリックを置くの巧妙な方法でしたが、今私たちはその決定の結果で永遠に生きる...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top