2

起初我得到了一些 ClassCastExceptions。当我去源码时,我发现我的值Map<Integer,Integer>实际上是字符串。

我做了以下实验来检查 PrimeFaces 的使用是否是我的问题:

<h:form>
    <p:spinner value="#{testBean.integer}" />
    <h:inputText value="#{testBean.integer}" />
    <p:spinner value="#{testBean.mapInt[0]}" />
    <h:inputText pt:type="number" value="#{testBean.mapInt[1]}" />
    <p:commandButton value="Read Map Values" action="#{testBean.checkTypes}" update="@form" />
    <p:messages />
</h:form>

我的测试豆:

@ManagedBean
@ViewScoped
public class TestBean implements Serializable {

    private HashMap<Integer, Integer> map;
    private Integer integer;

    @PostConstruct
    public void init() {
        map = new HashMap<>();
    }

    public void checkTypes() {
        addMsg(null, "integer - Class: " + integer.getClass().getSimpleName());
        for (Object key : map.keySet()) {
            Object o = map.get(key);
            addMsg(null, "map[" + key.toString() + "] - Class: " + o.getClass().getSimpleName());
        }
    }

    private static void addMsg(String client, String msg) {
        FacesContext.getCurrentInstance().addMessage(client, new FacesMessage(msg));
        System.out.println("msg [" + client + "]: " + msg);
    }

    //... getters/setters ...
}

消息显示:

integer - Class: Integer
map[0] - Class: String
map[1] - Class: String

第一个<h:inputText>甚至不需要直通来强制输入数字。

我猜 JSF 在内部使用反射将字段的输入字符串转换为正确的类型。如果是这样,那么也许泛型的类型擦除允许它把一个应该放在String哪里。Integer这可能就是为什么问题不会发生的原因integer,它是 type Integer,而不是泛型类型。

我说得对吗?

我的问题是:我怎样才能轻松解决它

我对 JSF 很陌生,我在寻找解决方案时听说过转换器。我是否必须创建一个自定义转换器来强制Integer.valueOf(String)对输入字段进行调用?我在哪里可以找到如何做到这一点?有没有更简单的解决方案

4

1 回答 1

5

您的具体问题是由 Java 泛型类型信息的性质引起的,该信息仅在编译时存在,因此在运行时完全不存在,并且 EL 表达式仅在运行时被评估,因此不在编译时被评估。实际上,EL 看不到任何通用类型信息。

所有 EL 在运行时看到的基本上都是 a Map,而不是Map<Integer, Integer>. 因此,除非您明确指定 a ,否则JSF/EL 将假定它与作为HTTP 请求参数Converter提取的提交值相同的标准类型: a 。String

解决方案比较简单:明确指定转换器。对于该类,您可以使用具有转换器 ID 的IntegerJSF 内置。IntegerConverterjavax.faces.Integer

<p:spinner value="#{testBean.mapInt[0]}" converter="javax.faces.Integer" />
于 2013-11-07T17:48:22.013 回答