JSF 2:レンダリングされた属性での列挙の使用

el enums jsf jsf-2
JSF 2:レンダリングされた属性での列挙の使用

列挙型に指定された値があるかどうかを宣言的に確認する方法はありますか。 例えば:

マネージドbeandですべての列挙値に対してこれをチェックするメソッドを定義するのは少し面倒です。

public boolean isStateIsError() {
  return current.getStatus() == Status.ERROR;
}

これを行うためのより短い/より良い方法はありますか?

  19  10


ベストアンサー

EL 3.0まで ELスコープで列挙型をインポートすることはできません。 ただし、文字列のように処理して比較することができます。 列挙定数値は以下のように引用する必要があります。

35


私はこの質問がもう少し古いことを知っていますが、同じ問題があり、共有したい別の解決策を見つけました:

カスタムELリゾルバーを作成し、* jsf elのオブジェクトとして列挙型とJava定数を使用します。

ただし、この方法で列挙型を使用するには、3つの手順を実行する必要があります。

1. ステップ-このクラスをコピーし、enumClassを介して「MY_ENUM」を置き換えます(上記の例では「Status」になります)

public class EnumCache {
    private Map  propertCache = new HashMap();
    private Map  baseCache = new HashMap();
    private static EnumCache staticEnumCache = null;

    public static EnumCache instance() {
        if (staticEnumCache == null) { staticEnumCache = new EnumCache(); }
        return staticEnumCache;
    }
    private EnumCache() {
        List> classes = new ArrayList>();
        classes.add(MY_ENUM.class);

        for(Class clazz : classes) {
            try {
                baseCache.put(clazz.getSimpleName(), clazz);
                Method m = clazz.getMethod("values", (Class[]) null);
                Enum<?>[] valueList = (Enum[]) m.invoke(null, (Object[]) null);
                for (Enum<?> en : valueList) {
                    propertCache.put(clazz.getSimpleName() + "." + en.name(), en);
                }
            } catch (Exception e) {
                System.err.println(clazz.getSimpleName(), e);
            }
        }
    }
    public Object getValueForKey(String key)  {
        return propertCache.get(key);
    }
    public Class getClassForKey(String key) {
        return baseCache.get(key);
    }
}

2. ステップ-このEnumResolverを追加-このクラスは、JSF式をキャッシュ内の列挙にマップします(ステップ1)

public class MyEnumResolver extends ELResolver {

    public Object getValue(ELContext context, Object base, Object property) {
        Object result = null;
        if (base == null) {
            result = EnumCache.instance().getClassForKey(property + "");
        } else if (base instanceof Class) {
            result = EnumCache.instance().getValueForKey(((Class) base).getSimpleName() + "." + property);
        }
        if (result != null) {
            context.setPropertyResolved(true);
        }
        return result;
    }

    public Class<?> getCommonPropertyType(ELContext context, Object base) {
        return null;
    }
    public Iterator getFeatureDescriptors(ELContext context, Object base) {
        return null;
    }
    public Class<?> getType(ELContext context, Object base, Object property) {
        return null;
    }
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        return false;
    }
    public void setValue(ELContext context, Object base, Object property, Object arg3) {
    }
}

*3. ステップ-EnumResolverをfaces-config.xml *に登録します

        com.asd.MyEnumResolver

NOTE If you want to access your java constants this way, you just have
enumCacheクラスのコンストラクターを拡張します。 この(テストされていない)例は動作するはずです:

baseCache.put(CLASS_WITH_CONSTANTS.getSimpleName(), clazz);
for (Field field : CLASS_WITH_CONSTANTS.getDeclaredFields()) {
    try {
        propertCache.put(CLASS_WITH_CONSTANTS.getSimpleName() + "."
                  + field.getName(), field.get(null));
    } catch (Exception e) { }
}

これが減ることを願っていますが、動作するコードが誰にも役立つことを願っています。

” ” ‘

更新

私はこの利点を見ます:

  1. jsfで文字列を使用する場合(viewController.current.status ==
    ‘ERROR_abcdefg’)、値のつづりを間違えても、すぐに認識できなくなります。 私の解決策では、enumを解決できなかったため、jsfファイルの読み込み中にエラーが発生しました。

  2. ソースコードで「ERROR」が列挙型の値であることがわかります
    “状態”。

  3. elの2つの値を比較すると、列挙型のクラスは
    比較しました。 たとえば、PersonState.ACTIVはAccounState.ACTIVと同じではありません。

  4. 列挙値をPersonState.ACTIVからに変更する必要がある場合
    PersonState.ACTIVATEDソースコードで文字列「PersonState.ACTIV」を検索できます。 「ACTIV」を検索すると、さらに多くの一致があります。

7


マップ内のすべての列挙キー(レンダリングされたUIコンポーネントで使用される)を「静的に」ダンプすることで同様の問題を解決し、静的な「getByKey」メソッドを使用してUIの値を実際のネイティブ列挙に変換しますセッター。指定された値が無効な場合に例外をスローします。

public enum ReportType {

    FILING("F", "Filings"),
    RESOLUTION("R", "Resolutions"),
    BASIS("B", "Bases"),
    STAFF("T", "Staff Counts"),
    COUNTS("I", "Counts");

    private String key;
    private String label;

    private static Map keyMap = new HashMap();

    static {
        for(ReportType type : ReportType.values()) {
            keyMap.put(type.getKey(), type);
        }
    }

    private ReportType(String _key, String _label) {
        this.key = _key;
        this.label = _label;

    }

    public String getKey() {
        return this.key;
    }

    public String getLabel() {
        return this.label;
    }

    public static List getValueList() {
        return Arrays.asList(ReportType.values());
    }

    public static ReportType getByKey(String _key) {
        ReportType result = keyMap.get(_key);

        if(result == null) {
            throw new IllegalArgumentException("Invalid report type key: " + _key);
        }

        return result;
    }
}

UI層では、列挙キーが値として使用され、列挙ラベルがラベルとして使用されます。

「マネージドBean」では、列挙型の「getValueList()」を使用して、列挙型をレンダリング可能なリストに変換します。

public List getAllReportTypes() {
    return ReportType.getValueList();
}

最後に、マネージドBeanの[g | s] etterは次のようになります。

public String getReportType() {
    return this.crtRptType.getKey();
}

public void setReportType(String _val) {
    this.crtRptType = ReportType.getByKey(_val);
}

1


私はそれを次の方法で行うことができると思います:

たとえば、列挙型のリストを返すメソッドをBeanで作成します

public Status[] getStatuses() {
  Status.values();
}

次に、このようにELでenumを使用できます

列挙型メンバーの順序は変更されないと仮定します(例: ここでstatuses [0]はERRORです)。 ただし、次のように位置を修正します。

public Status[] getStatuses() {
  Status myStatuses = new Status [2]; // or whatever number of statuses you are going to use in UI
  myStatuses [0] = Status.ERROR;
  myStatuses [1] = Status.RUNNING;
  return myStatuses;
}

これはまだ動的な解決策ではありませんが、ELでハードコーディングするよりも優れています。 ステータス(ロケール/翻訳に応じた列挙値)のローカライズを使用している場合、特に便利です。

1


以下を使用して同様の問題を解決します。

-1


タイトルとURLをコピーしました