为什么 JSF 将 String 值放在 Map<..., Integer> 中?以及如何解决它? [英] Why does JSF put String values in a Map&lt;..., Integer&gt;? And how to work around it?

查看:20
本文介绍了为什么 JSF 将 String 值放在 Map<..., Integer> 中?以及如何解决它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

At first I got some ClassCastExceptions. When I went to the source, I found out that the values in my Map<Integer,Integer> were in fact Strings.

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

I did the following experiment to check if the use of PrimeFaces was my problem:

<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>

我的TestBean:

My TestBean:

@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

第一个 甚至不需要传递来强制输入数字.

The first <h:inputText> didn't even need a passthrough to enforce a number input.

我猜 JSF 在内部使用反射将字段的输入字符串转换为正确的类型.如果是这样,那么泛型的类型擦除可能允许它把 String 放在 Integer 应该放在的地方.这可能就是 integer 不会出现问题的原因,它是 Integer 类型,而不是泛型类型.

I guess JSF uses reflection internally to convert the input string of the field to the right type. If so, then maybe type erasure of generics allows it to put a String where an Integer should be. This is probably why the problem does not happen with integer, which is of type Integer, not a generic type.

我说得对吗?

我的问题是:我怎样才能轻松地解决这个问题?

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

I'm pretty new to JSF, I heard about converters while looking for solutions. Do I have to create a custom converter to enforce a call to Integer.valueOf(String) on the input field? Where can I find how to do that? Is there a simpler solution?

推荐答案

您的具体问题是由于 Java 泛型类型信息的性质仅在编译时出现,因此在运行时完全不存在,并且 EL 表达式仅在运行时评估因此不在编译期间.实际上,EL 看不到任何泛型类型信息.

Your concrete problem is caused by the nature of Java generic type information being present during compiletime only and thus completely absent during runtime, and EL expressions being evaluated during runtime only and thus not during compiletime. In effects, EL doesn't see any generic type information.

所有 EL 在运行时看到的基本上都是 Map,而不是 Map.因此,除非您明确指定一个 Converter,否则 JSF/EL 将假定它与被提取为 HTTP 请求参数:String.

All EL sees during runtime is basically a Map, not a Map<Integer, Integer>. So, unless you explicitly specify a Converter, JSF/EL will assume it to be the same standard type as the submitted value which is extracted as HTTP request parameter: a String.

解决方法比较简单:显式指定一个转换器.对于 Integer 类,您可以使用 JSF 内置 IntegerConverter 具有转换器 ID javax.faces.Integer.

The solution is relatively simple: explicitly specify a converter. For the Integer class, you can use JSF builtin IntegerConverter which has the converter ID javax.faces.Integer.

<p:spinner value="#{testBean.mapInt[0]}" converter="javax.faces.Integer" />

这篇关于为什么 JSF 将 String 值放在 Map<..., Integer> 中?以及如何解决它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆