如何在f:selectItems中创建和使用通用枚举bean?

3

我有一个带有以下签名的通用类:

public abstract class EnumListBean<E extends Enum<E>> {

    public List<E> getEnumList() {
        //implementation details
    }

}

目前,为了访问具体的泛型参数的enumList属性,我必须定义一个空的子类:

@ManagedBean
@ApplicationScoped
public class ItemRarityBean  extends EnumListBean<Item.Rarity>{
}

这使得访问属性变得可能,例如:
<f:selectItems value="#{itemRarityBean.enumList}" var="rarity"
            itemLabel="#{rarity.readableName}" itemValue="#{rarity}" />

我在想是否真的需要声明一个派生bean,而不能直接访问泛型类作为bean:
<f:selectItems value="#{enumListBean<Item.Rarity>.enumList}" var="rarity"
                itemLabel="#{rarity.readableName}" itemValue="#{rarity}" />

您可能会发现OmniFaces <o:importConstants>很有用。 - BalusC
在您的特定情况下,即使EL可以访问具体参数化类型,它也可能没有用处。由于类型擦除,new EnumListBean<Item.Rarity>.getEnumList() 没有办法返回除 new EnumListBean<SomethingElse>.getEnumList() 之外的任何内容,除非传递一个类型标记。您可以做的是伪造一个索引属性,并且拥有一个可由 Class 索引的 bean,该 bean 返回其值列表,但我不确定您是否可以在 EL 中使用类字面量。 - millimoose
@BalusC 哇,几乎就是我想要实现的东西。 <o:importConstants> 导入的枚举是否可以与 <f:selectItems> 一起用作列表? - Sebastian Hoffmann
@BalsusC:哦,我刚看到第一个示例。你可能想把这个发布为答案? - Sebastian Hoffmann
2个回答

4

在EL中不能使用泛型。EL是一种基于反射的运行时语言。你知道,泛型只在编译时可用,而不是在运行时。

对于您特定的目的,使用OmniFaces <o:importConstants>可能更容易。

<o:importConstants type="com.example.Item$Rarity" var="Rarity" />
...
<h:selectOneMenu>
    <f:selectItems value="#{Rarity}" />
</h:selectOneMenu>

(var属性不是必须的,但如果你想要以可读性高的方式引用它的话,你需要写成#{Item$Rarity}。如果你的Rarity枚举是一个独立的枚举而不是内部枚举,那么你可以直接使用type="com.example.Rarity")

这个设计将其视为Map<String, Rarity>,而不是List<Rarity>之类的。所以如果你打算访问<f:selectItems>中的var属性中的单独项,以便访问特定的枚举方法,则需要显式地迭代Map#values()(这需要EL 2.2支持)。

<h:selectOneMenu>
    <f:selectItems value="#{Rarity.values()}" var="rarity" itemValue="#{rarity}" itemLabel="#{rarity.readableName}" />
</h:selectOneMenu>

2

是的,你必须这样做。因为实例化抽象类没有意义。


1
这个类在当前的用例中只是抽象的。我可以自由地更改声明。 - Sebastian Hoffmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接