在p:dataTable过滤器中显式使用隐式JSF转换器javax.faces.convert.EnumConverter

Tin*_*iny 2 datatable jsf enums converter primefaces

枚举:

public enum OrderStatus {

    New("New"),
    Paid("Paid"),
    Shipped("Shipped"),
    Completed("Completed");

    private final String label;

    private OrderStatus(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }
}
Run Code Online (Sandbox Code Playgroud)

enum<p:dataTable>过滤器中使用类型如下.

<p:dataTable var="row"
             value="#{testBacking}"
             lazy="true"
             rows="10"
             widgetVar="dataTableUIWidget">

    <p:column id="id" headerText="Id">
        <h:outputText value="#{row.orderId}"/>
    </p:column>

    <p:column headerText="Order Status" filterBy="#{row.orderStatus}">
        <f:facet name="filter">
            <p:selectOneMenu onchange="PF('dataTableUIWidget').filter();">
                <f:selectItem itemLabel="Select" itemValue=""/>

                <f:selectItems var="orderStatus"
                               value="#{enumBean.orderStatus}" 
                               itemLabel="#{orderStatus.label}"/>
            </p:selectOneMenu>
        </f:facet>

        <h:outputText value="#{row.orderStatus}"/>
    </p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)

row.orderStatusenum其关联的JPA实体中的上述类型.

过滤器与<p:selectOneMenu>需要javax.faces.convert.EnumConverter明确指定相关联,因为它的值没有绑定到支持bean属性(否则,根据相关辅助bean中属性的类型,适当的转换器将根据其自身隐式地适当地发挥其作用) .

我希望提到转换器如下

<f:converter converterId="javax.faces.Enum"/>
Run Code Online (Sandbox Code Playgroud)

应该像其他隐式转换器一样工作

然而,这会引起问题(<f:converter>如上所述).

严重:JSF1006:无法实例化javax.faces.Enum类型的转换器

这个转换器有什么问题?我正在寻找一个可行的解决方案.

使用PrimeFaces 5.2 final/Mojarra 2.2.12.


附加:

转换器指定javax.faces.EnumconverterId.

public class EnumConverter implements Converter, PartialStateHolder {

    public static final String CONVERTER_ID = "javax.faces.Enum";
    public static final String ENUM_ID = "javax.faces.converter.EnumConverter.ENUM";
    public static final String ENUM_NO_CLASS_ID = "javax.faces.converter.EnumConverter.ENUM_NO_CLASS";
    private Class<? extends Enum> targetClass;
    private boolean isTransient;
    private boolean initialState;

    public EnumConverter() {}
}
Run Code Online (Sandbox Code Playgroud)

因此,这应该通过指定工作javax.faces.EnumconvertId<f:converter>是其他隐JSF转换器.

在上面的测试用例中使用的bean(完全可选的同行评审):

@Named
@ViewScoped
public class TestBacking extends LazyDataModel<OrderTable> implements Serializable {

    @Inject
    private OrderService orderService;
    private static final long serialVersionUID = 1L;

    public TestBacking() {}

    @Override
    public List<OrderTable> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {

        if (MapUtils.isNotEmpty(filters)) { // Debugging purpose only.
            System.out.println("Enum filter : " + (filters.get("orderStatus") instanceof OrderStatus));
            System.out.println("Filter value : " + filters.get("orderStatus"));
        }

        int rowCount = MapUtils.isNotEmpty(filters) ? orderService.rowCount(filters).intValue() : orderService.rowCount().intValue();
        setRowCount(rowCount);

        return orderService.getList(first, pageSize, null, filters);
    }
}
Run Code Online (Sandbox Code Playgroud)

stdout内部语句load()方法显示如下输出.

Enum filter : false
Filter value : New
Run Code Online (Sandbox Code Playgroud)

(显然filters.get("orderStatus") instanceof OrderStatus返回false,因为过滤器组件<p:selectOneMenu>没有通过转换器.它只是在String没有转换的情况下返回).

Bal*_*usC 8

EnumConverter是一个特殊的转换器,只能用Class<E>as参数构造(最终设置为targetClass).没有它,转换器将无法工作.遗憾的是,它并不适用于所有枚举(即它实际上不是"通用枚举转换器").在那里你假设在枚举上进行隐式/自动转换,它实际上是由EL强制完成的,而不是由JSF完成的EnumConverter.只要目标类型可以解析为枚举,EL确实支持枚举.

要显式使用JSF枚举转换器,您基本上需要EnumConverter像下面一样扩展以将目标枚举传递给c'tor(无需覆盖getAsString/Object()方法):

@FacesConverter(value="orderStatusConverter")
public class OrderStatusConverter extends EnumConverter {

    public OrderStatusConverter() {
        super(OrderStatus.class);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后引用它:

<f:converter converterId="orderStatusConverter" />
Run Code Online (Sandbox Code Playgroud)

不要忘记改变<f:selectItem itemValue="">itemValue="#{null}",或者你会得到一个ClassCastExceptionjava.lang.String.

如果您碰巧使用OmniFaces,您也可以使用其通用枚举转换器:

<f:converter converterId="omnifaces.GenericEnumConverter" />
Run Code Online (Sandbox Code Playgroud)