List< Integer>收到List< String> [英] List<Integer> received List<String>

查看:95
本文介绍了List< Integer>收到List< String>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我在使用JSF 2.0(使用Primefaces)的Java运行时中发现了一个错误,在这个项目中,我使用的是JSF 2.0 Primefaces和CDI。

I think that I found a error in runtime of Java with JSF 2.0 (Using Primefaces), in this project I'm using JSF 2.0 Primefaces and CDI.

恢复问题,我在业务类Role中有一个方法设置器,该方法接收了一个List,但是JSF对此设置了一个ArrayList。
Java应该抛出异常还是至少不应该找到匹配的方法?
此处是:

Resuming the problem, I have a method setter in my business class Role that received a List, but the JSF is setting a ArrayList on that. Should the java throw a exception or at least should not find a method that matches? here is:

public void setAcl(List<Integer> acl) {
    this.acl = acl;
    System.out.println("Received: " + this.acl);
    for(Object i : this.acl) {
        System.out.println(i.getClass() + " > " + i);
    }
}

此方法的输出是:


Received: [1, 5]
class java.lang.String > 1
class java.lang.String > 5

当我尝试在foreach中使用这种情况时:

And when I try to use in foreach like this:

for(Integer i : this.acl) {
    System.out.println(i.getClass() + " > " + i);
}

投掷

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

您能解释一下这是怎么回事吗?在JSF或Java上是否有错误?还是我被误解了?

Can you explain what is going on here? Is it a error on JSF or Java? Or is my misunderstood?

首先我有一个UI JSF(.xhtml),它的 p:selectManyCheckbox ,这个manyCheckbox从managedbean接收一个枚举PontoSenha枚举数组(使用枚举的方法values()),并将值定义为itemValue和itemLabel。
请遵循manyCheckbox的代码:

First I have a UI JSF (.xhtml) that has a p:selectManyCheckbox, this manyCheckbox receive a array of enum PontoSenha (using the enum's method values() ) from managedbean and define the values to itemValue and itemLabel. Follow the code of manyCheckbox:

<p:selectManyCheckbox id="acl" value="#{roleController.role.acl}" layout="grid" columns="4" required="true" requiredMessage="Selecione pelo menos um ponto de senha" >  
    <f:selectItems value="#{roleController.pontosSenha}" var="pontoSenha" itemValue="#{pontoSenha.pontoSenha}" itemLabel="#{pontoSenha.descricao}" />  
</p:selectManyCheckbox>

枚举PontoSenha的声明:

Declaration of enum PontoSenha:

package br.com.bsetechnology.atacadao.business;
public enum PontoSenha {
    CADASTRO_FORNECEDOR(1, "Cadastrar fornecedor"),
    CADASTRO_LOJA(2, "Cadastrar loja"),
    CADASTRO_PRODUTO(3, "Cadastrar produto"),
    RELATORIO(4, "Gerar relatório"),
    SEGURANCA_GRUPOS(5, "Gerenciar grupos de usuário"),
    SEGURANCA_USUARIOS(6, "Gerenciar usuários");

    private int pontoSenha;
    private String descricao;

    private PontoSenha(int pontoSenha, String descricao) {
        this.pontoSenha = pontoSenha;
        this.descricao = descricao;
    }

    public int getPontoSenha() {
        return pontoSenha;
    }

    public String getDescricao() {
        return descricao;
    }

    @Override
    public String toString() {
        return String.format("%02d - %s", pontoSenha, descricao);
    }
}

ManagedBean的声明

Declaration of the ManagedBean

package br.com.bsetechnology.atacadao.controller;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.inject.Inject;
import javax.inject.Named;
import br.com.bsetechnology.atacadao.business.PontoSenha;
import br.com.bsetechnology.atacadao.business.Role;
import br.com.bsetechnology.atacadao.core.FacesUtil;
import br.com.bsetechnology.atacadao.dao.RoleDAO;

@Named("roleController")
@RequestScoped
public class RoleController {

    @Inject
    private RoleDAO roleDao;
    private Role role;

    public void setRoleDao(RoleDAO roleDao) {
        this.roleDao = roleDao;
    }

    public Role getRole() {
        if(role == null)
            role = new Role();
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public PontoSenha[] getPontosSenha() {
        return PontoSenha.values();
    }

    public List<Role> getAll() {
        return roleDao.getAll();
    }

    public void salva() {
        System.out.println("Salvando");
        boolean resultAction = false;

        if(role.getCodigo() > 0) {
            resultAction = roleDao.update(role);
        } else {
            resultAction = roleDao.insert(role);
        }

        if(resultAction) {
            role = new Role();
            FacesUtil.addMessage(FacesMessage.SEVERITY_INFO, "Grupo salvo com sucesso.", null);
        } else {
            FacesUtil.addMessage(FacesMessage.SEVERITY_WARN, "Grupo não foi salvo.", null);
        }
    }
}

商务舱角色

package br.com.bsetechnology.atacadao.business;
import java.util.ArrayList;
import java.util.List;

public class Role {
    private int codigo;
    private String descricao;
    private List<Integer> acl;

    public Role() {
        acl = new ArrayList<Integer>();
    }

    public Role(int codigo, String descricao, List<Integer> acl) {
        setCodigo(codigo);
        setDescricao(descricao);
        setAcl(acl);
    }

    public int getCodigo() {
        return codigo;
    }

    public void setCodigo(int codigo) {
        this.codigo = codigo;
    }

    public String getDescricao() {
        return descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

    public List<Integer> getAcl() {
        return acl;
    }

    public void setAcl(List<Integer> acl) {
        this.acl = acl;
        System.out.println("Received: " + this.acl);
        for(Object i : this.acl) {
            System.out.println(i.getClass() + " > " + i);
        }
    }

    public void addPontoSenha(int pontoSenha) {
        this.acl.add(pontoSenha);
    }

    public void remPontoSenha(int pontoSenha) {
        this.acl.remove(pontoSenha);
    }
}

我用来注册角色的页面JSF(模板.xhtml仅是HTML和CSS):

The page JSF that I use to register roles (template.xhtml is only HTML and CSS):

<ui:composition template="/WEB-INF/template.xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui">

    <ui:define name="body-content">
    <div class="row">
        <h:form id="formGrupo" class="form-horizontal"><fieldset>
        <p:panel header="Edição de grupo de usuário" >
            <div class="control-group">
                <h:outputLabel for="codigo" value="Código" readonly="" styleClass="control-label" />
                <div class="controls">
                    <h:inputText id="codigo" class="form-control" value="#{roleController.role.codigo}"
                        style="width:100px;text-align:right;" />
                </div>
            </div>
            <div class="control-group">
                <h:outputLabel for="descricao" value="Descrição" styleClass="control-label" />
                <div class="controls">
                    <h:inputText id="descricao" class="form-control" value="#{roleController.role.descricao}"
                        required="true" maxlength="20" requiredMessage="Descrição obrigatória" converterMessage="Descrição inválida"  />
                    <h:message for="descricao" class="error" />
                </div>
            </div>
            <div class="control-group">
                <h:outputLabel value="Pontos de senha" styleClass="control-label" />
                <div class="controls checkbox">
                    <p:selectManyCheckbox id="acl" value="#{roleController.role.acl}" layout="grid" columns="4"
                        required="true" requiredMessage="Selecione pelo menos um ponto de senha" >  
                        <f:selectItems value="#{roleController.pontosSenha}" var="pontoSenha" itemValue="#{pontoSenha.pontoSenha}" itemLabel="#{pontoSenha.descricao}" />  
                    </p:selectManyCheckbox>
                    <h:message for="acl" errorClass="error" />
                </div>
            </div>
            <div class="form-actions">
                <hr/>
                <p:commandLink value="Salvar" styleClass="btn btn-primary" style="color:#fff;" action="#{roleController.salva}" update=":formGrupo,:formTable:tblRoles">
                </p:commandLink>
            </div>
            <p:messages globalOnly="true" showDetail="false" closable="true" />
        </p:panel>
        </fieldset></h:form>
    </div>
    <br/>
    <div class="row">               
        <h:form id="formTable" styleClass="form-horizontal"><fieldset>
            <p:panel header="Grupos de usuários">
                <p:dataTable id="tblRoles" var="role" value="#{roleController.all}" rowKey="#{role.codigo}" stickheader="true" >

                    <p:column headerText="Código" width="20">
                        <h:outputText value="#{role.codigo}" />
                    </p:column>
                    <p:column headerText="Descrição">
                         <h:outputText value="#{role.descricao}" />
                    </p:column>                 
                    <p:column width="200">      
                        <p:commandLink value="Editar" class="btn btn-success btn-sm" style="color:#fff;margin-left:5px;" update=":formGrupo">
                            <f:setPropertyActionListener value="#{role}" target="#{roleController.role}" />
                        </p:commandLink>
                        <p:commandLink value="Excluir" styleClass="btn btn-danger btn-sm" style="color:#fff;margin-left:5px;" />  
                    </p:column>
                </p:dataTable>

            </p:panel>
        </fieldset></h:form>
    </div>
    </ui:define>
</ui:composition>

完整打印堆栈跟踪

Jan 29, 2014 10:59:43 PM com.sun.faces.context.AjaxExceptionHandlerImpl handlePartialResponseError
SEVERE: javax.faces.component.UpdateModelException: javax.el.ELException: /seguranca/grupos.xhtml @27,87 value="#{roleController.role.acl}": Error writing 'acl' on type br.com.bsetechnology.atacadao.business.Role
    at javax.faces.component.UIInput.updateModel(UIInput.java:867)
    at javax.faces.component.UIInput.processUpdates(UIInput.java:749)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at org.primefaces.component.panel.Panel.processUpdates(Panel.java:288)
    at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1286)
    at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1254)
    at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at br.com.bsetechnology.atacadao.core.AccessControlFilter.doFilter(AccessControlFilter.java:31)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
Caused by: javax.el.ELException: /seguranca/grupos.xhtml @27,87 value="#{roleController.role.acl}": Error writing 'acl' on type br.com.bsetechnology.atacadao.business.Role
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:139)
    at javax.faces.component.UIInput.updateModel(UIInput.java:832)
    ... 30 more
Caused by: javax.el.ELException: Error writing 'acl' on type br.com.bsetechnology.atacadao.business.Role
    at javax.el.BeanELResolver.setValue(BeanELResolver.java:153)
    at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
    at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
    at org.apache.el.parser.AstValue.setValue(AstValue.java:218)
    at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:253)
    at org.jboss.weld.el.WeldValueExpression.setValue(WeldValueExpression.java:64)
    at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
    ... 31 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at br.com.bsetechnology.atacadao.business.Role.setAcl(Role.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at javax.el.BeanELResolver.setValue(BeanELResolver.java:142)
    ... 37 more


推荐答案

这是由多种技术限制共同导致的和事实。

This is caused by a combination of several technical limitations and facts.


  • 在Java中,泛型是编译时语法糖。最终,当编译Java类时,所有通用类型信息都会丢失。因此,在运行时期间,没有任何方法可以传递 List 实例中的任何泛型类型信息。

  • In Java, generics are compile time syntactic sugar. Ultimately, when a Java class is compiled, all generic type information is lost. So, during runtime there's no means of any generic type information in the List instance being passed around.

表达式语言(EL,#{} )在运行时使用Java Reflection API运行,在您的特殊情况下只能看到 List ,而不是 List&

The expression language (EL, #{}) runs during runtime using Java Reflection API and sees in your particular case only a List, not a List<Integer>.

生成的HTML输出和获得的HTTP请求参数在Java透视图中基本上是 String s。

The generated HTML output and the obtained HTTP request parameters are in Java perspective basically Strings.

只要您未明确指定JSF 转换器 String 到所需类型之间,JSF将让EL (阅读:Reflection API)将未转换的提交的 String 值添加到 List

As long as you don't explicitly specify a JSF Converter between String to the desired type, JSF will let EL (read: Reflection API) add the unconverted submitted String value to the List.

为了使提交的值最终成为模型中的 Integer ,您需要共有3个选项:

In order to get the submitted value to end up as Integer in the model, you have 3 options:


  1. 显式指定 String 整数。幸运的是,JSF有一个内置的 IntegerConverter ,其转换器ID为 javax.faces.Integer 。因此,您需要做的就是在输入组件的 converter 属性中指定它。

  1. Explicitly specify a converter for String to Integer. Fortunately, JSF has a built-in one, the IntegerConverter which has the converter ID javax.faces.Integer. So all you need to do is specifying it in the input component's converter attribute.

 <p:selectManyCheckbox ... converter="javax.faces.Integer">



  • 使用 Integer [] 而不是 List< Integer> 作为模型属性。

  • Use Integer[] instead of List<Integer> as model property.

     private Integer[] acl;
    

    这样,EL可以看到所需的类型(阅读:Reflection API),它将使用内置的-in转换器。

    This way the desired type is visible to EL (read: Reflection API) and it'll perform automatic conversion using the built-in converter.

    至少升级到JSF 2.3。根据规格问题1422 UISelectMany当使用 Collection 时,组件将具有与 OmniFaces SelectItemsConverter

    Upgrade to at least JSF 2.3. As per spec issue 1422 the UISelectMany components will have automatic conversion when a Collection is used, using the same basic principle as OmniFaces SelectItemsConverter.

    另请参见 UISelectMany javadoc

    See also UISelectMany javadoc.


    获取转换器使用以下算法:


    • 如果组件具有附加的转换器,请使用

    如果没有,请查找 ValueExpression 作为值(如果有) 。 ValueExpression 必须指向以下内容:

    If not, look for a ValueExpression for value (if any). The ValueExpression must point to something that is:


    • 基元数组(例如 int [] )。查找此原始类型的已注册按类转换器

    • An array of primitives (such as int[]). Look up the registered by-class Converter for this primitive type.

    一个数组对象(例如 Integer [] String [] )。查找注册的按类转换器以获取基础元素类型。

    An array of objects (such as Integer[] or String[]). Look up the registered by-class Converter for the underlying element type.

    A java.util.Collection 。不要转换值。相反,将提供的一组可用选项完全转换为字符串,就像在渲染响应期间所做的那样,对于与提交值的任何匹配,请将可用选项作为对象添加到集合中。

    A java.util.Collection. Do not convert the values. Instead, convert the provided set of available options to string, exactly as done during render response, and for any match with the submitted values, add the available option as object to the collection.

    如果出于任何原因,转换器找不到,假设类型为String数组。

    If for any reason a Converter cannot be found, assume the type to be a String array.

    这篇关于List&lt; Integer&gt;收到List&lt; String&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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