使用转换器时未调用 SelectOneMenu setter

SelectOneMenu the setter is not being called when using a converter

我创建了一个简单的转换器,我正在读书,下面的代码应该可以工作,但是当我 select 一个项目时,它没有被设置为值。 我在 setter 上放置了一个断点,当 select selectOneMenu.

中的一个项目时,它没有被击中
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title></title>
    </h:head>
    <h:body>
        <h:form>
            dfdfd
            <p:selectOneMenu value="#{selecaoController.selectedTag}" var="t"
                             converter="tagConverter">
                
                <f:selectItem itemLabel="Select One" itemValue="" />
                <f:selectItems value="#{selecaoController.tagPojos}" var="tag"
                               itemLabel="#{tag.label}" itemValue="#{tag}" />
                <p:column>
                    #{t.label} - #{t.value}
                </p:column>
                <p:column>
                    <p:graphicImage value="/resources/images/tags/#{t.value}.png"
                                    width="32px" height="32px"/>
                </p:column>
                
                <p:ajax event="change" process="@this" update="msg" />
                
            </p:selectOneMenu>
     
            <p:outputLabel id="msg" value="#{selecaoController.selectedTag.label}" />
            
        </h:form>
    </h:body>
</html>

班级。

package com.packtpub.pfbg.controllers;


import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author diego
 */

@FacesConverter(value = "tagConverter")
public class TagConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        
       if(value == null || value.trim().equals("")){
           return null;
       } 
       try{
           Tag t1 = new Tag(1, "JavaScript", "javascript");
           Tag t2 = new Tag(2, "C#", "C#");
          Tag t3 = new Tag(3, "Java", "Java");
          Tag t4 = new Tag(4, "Angular", "angular");


           List<Tag> ts = new ArrayList<Tag>();
           ts.add(t1);
           ts.add(t2);
           ts.add(t3);
           ts.add(t4);

           int id = Integer.parseInt(value);
           List<Tag> tags = ts;
           
           for(Tag t : tags){
               
               if(t.getId() == id){
                   return t;

               }
           }         
       }
        catch(NumberFormatException ex){
              throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "conversion erro", "Not a valid tag"));
          }
       return null;
    }

    
    
    
    

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        
        if(value == null || value.equals("")){
            return "";
        }else{
            return String.valueOf(((Tag) value).getId());
        }
        
    }
    
}

超一流

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.packtpub.pfbg.controllers;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 *
 * @author diego
 */

@ManagedBean
@RequestScoped
public class SelecaoController {
    
  private List<Tag> tagPojos;
  private Tag selectedTag;
    
   public SelecaoController(){
       
       tagPojos = new ArrayList<Tag>();
       tagPojos.add(new Tag(1, "JavaSE", "java-se", "Java Programming Language"));
       tagPojos.add(new Tag(2, "JavaEE", "javaEE", "Java Enterprise"));
       tagPojos.add(new Tag(3, "Spring", "Spring", "Spring Framework"));

   } 

    public List<Tag> getTagPojos() {
        return tagPojos;
    }

    public void setTagPojos(List<Tag> tagPojos) {
        this.tagPojos = tagPojos;
    }

    public Tag getSelectedTag() {
        return selectedTag;
    }

    public void setSelectedTag(Tag selectedTag) {
        this.selectedTag = selectedTag;
    }
   
   
    
}

如果您为字段添加 growlmessage 或提高日志级别,您将在 select 项目后看到此错误:

Validation Error: Value is not valid

问题是 selected 值不在列表中。 在列表中搜索的 jsf 代码迭代 selectOneMenu 的所有子项并检查从转换器编辑的元素 return 是否等于其中任何一个。
您有很多方法可以让您的代码正常工作:

  1. 由于您正在使用另一个列表,您可以覆盖 Tag class 中的 equals 方法,例如仅检查 id 值,如果它是键,以便即使没有相同的对象也能获得匹配

  2. 在转换器中迭代相同的列表,return 完全相同的对象

对于解决方案 2,如果您将控制器移动到 view scope,此代码有效,但也有直接来自组件变量和 request scope.

的方法
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
SelecaoController viewScopedBean = (SelecaoController) viewMap.get("selecaoController");
for (Tag t : viewScopedBean.getTagPojos()) {
    if (t.getId() == id) {
        return t;
    }
}