当前位置: 首页 > 知识库问答 >
问题:

列表接收列表

傅浩漫
2023-03-14

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

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

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中使用这样的:

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上的错误?还是我被误解了?

首先,我有一个UI JSF(.xhtml),它有一个p:selectManyCheckbox,这个manyCheckbox从managedbean接收一个enum PontoSenha数组(使用enum的方法values()),并定义itemValue和itemLabel的值。遵循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>

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

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(template.xhtml只有超文本标记语言和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

共有1个答案

傅越
2023-03-14

这是由几个技术限制和事实综合造成的。

>

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

生成的超文本标记语言输出和获得的HTTP请求参数在Java角度基本上Strings。

只要你没有明确地指定一个JSF转换器,将字符串转换成所需的类型,JSF就会允许EL(读取:反射API)将未转换的提交的字符串值添加到列表

为了使提交的值最终在模型中作为整数,您有3个选项:

>

  • 显式指定StringIntger的转换器。幸运的是,JSF有一个内置的IntgerConverter,它具有转换器IDjavax.faces.整数。所以您需要做的就是在输入组件的转换器属性中指定它。

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

    使用整数[]代替列表

     private Integer[] acl;
    

    这样,所需的类型对EL是可见的(读取:反射API),它将使用内置转换器执行自动转换。

    升级到至少JSF 2.3。根据规范问题1422,使用Collection时,UISelect许多组件将具有自动转换,使用与OmniFacesSelectItemsConverter相同的基本原理。

    另请参见UISelectManyjavadoc。

    使用以下算法获取转换器

    >

  • 如果组件附带了一个转换器,请使用它。

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

    >

    对象数组(例如Integer[]String[])。在registered by classConverter中查找底层元素类型。

    Ajava。util。收藏。不要转换这些值。相反,将提供的可用选项集转换为字符串,就像在渲染响应期间所做的那样,如果与提交的值匹配,请将可用选项作为对象添加到集合中。

    如果由于任何原因找不到转换器,则假定该类型为字符串数组。

  •  类似资料:
    • 我有包含项目数组的类存储。 每个项目(类项目)有不同的体积,我正在添加项目到商店。假设我有20个项目,我把10个添加到2或3个不同的商店,我必须根据这些项目的数量在商店中排序。

    • 当流过< code>List时,如何将输出收集到一个链表中? 我尝试了以下方法: 但是这给了 java.util.数组列表不能转换为 java.util.链接列表.

    • 有时你需要在一个表单中以单一的形式处理多个模型。例如,有多个设置, 每个设置存储为一个 name-value,并通过 Setting 活动记录 模型来表示。这种形式也常被称为“列表输入”。与此相反, 处理不同模型的不同类型,在 多模型同时输入章节中介绍。 下面展示了如何在 Yii 中收集列表输入。 在三种不同的情况下,所需处理的略有不同: 从数据库中更新一组固定的记录 创建一个动态的新记录集 更新

    • 现阶段 Tongji API 提供给您的接口有: 获取站点列表 百度商业账号 https://api.baidu.com/json/tongji/v1/ReportService/getSiteList 百度账号 https://openapi.baidu.com/rest/2.0/tongji/config/getSiteList 获取报告数据 百度商业账号 https://api.baid

    • 接待组列表 接待组列表是用户已经咨询的接待组的列表 如果是B2B2C的客户,咨询列表的实现方式可以参考我们的demo中的3.0_Visitor包中的newIntegrate/templatelist下的两个类; 其中获取本地消息列表数据的监听接口为OnRefreshCurrentMsgListener; 注册监听方法: Ntalker.getInstance().getConversationLi

    •  介绍 Task3主要是珠海的任务系统 Host 172.17.6.153 task3.game.duowan.com 172.17.6.153 adm.task3.game.yy.com 接口状态 状态码 说明 200 请求成功 404 活动不存在 403 活动未开启 405 游戏入口受限/未登陆 406 任务不属于该活动 407 角色无效 408 未参加任务 409 未通过防刷验证 411