p:selectManyMenu和@FacesConverter(forClass = Clazz.class)

时间:2015-08-06 11:50:54

标签: jsf primefaces converter selectmanymenu

<p:selectManyMenu id="colourList"
                  var="color"
                  value="#{testBean.selectedColours}"
                  converter="#{colourConverter}"
                  showCheckbox="true"
                  required="true"
                  label="Colour"
                  style="overflow: auto; width: 317px; background-color: white; max-height: 200px;">

    <f:selectItems var="colour"
                   value="#{testBean.colours}"
                   itemLabel="#{colour.colourHex}"
                   itemValue="#{colour}"/>
    <p:column>
        <span style="display: inline-block; width: 275px; height: 20px; background-color:\##{color.colourHex}; border: 1px solid black;"
              title="Name: #{color.colourName} | Hex: #{color.colourHex}" />
    </p:column>
</p:selectManyMenu>

<p:commandButton value="Submit" actionListener="#{testBean.action}"/>
如果有人想将这个例子付诸实践,那么

CSS保持不变。它将显示三种基本颜色(RGB),前面有复选框,如下所示。

enter image description here

托管bean:

@Named
@ViewScoped
public class TestBean implements Serializable {

    @Inject
    private DataStore dataStore;
    private List<Colour> colours; //Getter & setter.
    private List<Colour> selectedColours; //Getter & setter.
    private static final long serialVersionUID = 1L;

    public TestBean() {}

    @PostConstruct
    private void init() {
        colours = dataStore.getColours();
    }

    public void action() {
        for (Colour colour : selectedColours) {
            System.out.println("colourName : "
                    + colour.getColourName()
                    + " : colourHex : "
                    + colour.getColourHex());
        }
    }
}

如果从converter="#{colourConverter}"移除<p:selectManyMenu>属性,则会导致java.lang.ClassCastException抛出action(),即使转换器使用{{1}进行修饰}}

@FacesConverter(forClass = Colour.class)

它似乎是泛型类型的橡皮擦问题(java.lang.ClassCastException: java.lang.String cannot be cast to com.example.Colour 的泛型类型参数在运行时被删除,因此它变成了无类型的List<Colour>)。

然后

List应该可以工作,但尝试时不会调用Colour[]方法本身。

为什么需要明确提及转换器的确切原因是什么?

其他:

转换器:

action()

应用程序作用域bean,其中维护@Named @ApplicationScoped @FacesConverter(forClass = Colour.class) public class ColourConverter implements Converter { @Inject private DataStore dataStore; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null || value.isEmpty()) { return null; } try { long parsedValue = Long.parseLong(value); if (parsedValue <= 0) { throw new ConverterException("FacesMessage"); } Colour entity = dataStore.findColourById(parsedValue); if (entity == null) { throw new ConverterException("FacesMessage"); } return entity; } catch (NumberFormatException e) { throw new ConverterException("FacesMessage", e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value == null) { return ""; } if (!(value instanceof Colour)) { throw new ConverterException("Message"); } Long id = ((Colour) value).getColourId(); return id != null ? id.toString() : ""; } }

List<Colour>

域模型类:

@Named
@ApplicationScoped
public class DataStore {

    private List<Colour> colours;

    public DataStore() {}

    @PostConstruct
    private void init() {
        colours = new ArrayList<>();

        Colour colour = new Colour();
        colour.setColourId(1L);
        colour.setColourName("Red");
        colour.setColourHex("FF0000");
        colours.add(colour);

        colour = new Colour();
        colour.setColourId(3L);
        colour.setColourName("Green");
        colour.setColourHex("008000");
        colours.add(colour);

        colour = new Colour();
        colour.setColourId(2L);
        colour.setColourName("Blue");
        colour.setColourHex("0000FF");
        colours.add(colour);
    }

    public Colour findColourById(Long id) {
        for (Colour colour : colours) {
            if (colour.getColourId().equals(id)) {
                return colour;
            }
        }

        return null;
    }

    public List<Colour> getColours() {
        return colours;
    }
}

1 个答案:

答案 0 :(得分:3)

这个问题是双重的。

第一个问题是EL无法确定模型值类型,因为泛型类型信息在运行时会丢失。它基本上变成Object.class。您基本上需要将List<Colour>替换为Colour[]。这个问题详细解答了这个问题:UISelectMany on a List<T> causes java.lang.ClassCastException: java.lang.String cannot be cast to T

第二个问题是PrimeFaces InputRenderer有一个错误,它在找到转换器之前没有考虑数组类型。下面的行号匹配5.2

156    protected Converter findImplicitConverter(FacesContext context, UIComponent component) {
157        ValueExpression ve = component.getValueExpression("value");
158
159        if(ve != null) {
160            Class<?> valueType = ve.getType(context.getELContext());
161                
162            if(valueType != null)
163                return context.getApplication().createConverter(valueType);
164        }
165
166        return null;
167    }

在您的具体情况下,valueTypeColour[].class而不是Colour.class。这就解释了为什么它无法找到与Colour.class相关联的转换器。在创建转换器之前,应检查valueType是否为array type,如果是,则从中提取component type

if (valueType.isArray()) {
    valueType = valueType.getComponentType();
}

您最好向PrimeFaces人员报告这是一个错误,以及它在<h:selectManyMenu>等标准组件中运行良好的事实。同时,最好的办法就是明确注册转换器。