primefaces: SelectOneMenu: throws ClassCastException if it is used with converter and editable="true"

1) Environment

  • PrimeFaces version: 6.2
  • Application server: Glassfish 4.1, Wildfly 10.1.0.Final
  • Affected browsers: Chrome

2) Expected behavior

No exception appears

3) Actual behavior

SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-8) java.lang.ClassCastException: com.tsystems.ima.sandbox.NamedObject cannot be cast to java.lang.String
	at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:318)
	at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.getConvertedValue(SelectOneMenuRenderer.java:80)

appears after selecting a value from drop down list

4) Steps to reproduce

  1. Open page
  2. Select ‘second’ value - exception is thrown

5) Sample XHTML

<!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://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://primefaces.org/ui">
<h:head>
    
</h:head>
<h:body>
    <h:form id="box">
        <p:outputLabel value="Check select"/>
        <div>
            <p:selectOneMenu id="pdfSelZoom"
                             value="#{namedObjectBean.namedObject}" editable="true"
                             converter="namedObjectConverter">
                <f:selectItems value="#{namedObjectBean.selectItems}"/>
                <p:ajax process="@this" update="selectedValue"/>
            </p:selectOneMenu>
        </div>
        <div>
            <p:outputLabel id="selectedValue" value="Selected value: #{namedObjectBean.namedObject.name}"/>
        </div>
    </h:form>
</h:body>
</html>

6) Sample bean

@ManagedBean
public class NamedObjectBean {
    private NamedObject namedObject = new NamedObject("first");

    private List<SelectItem> selectItems;

    public NamedObject getNamedObject() {
        return namedObject;
    }

    public void setNamedObject(NamedObject namedObject) {
        this.namedObject = namedObject;
    }

    public List<SelectItem> getSelectItems() {
        if (selectItems == null) {
            selectItems = Arrays.asList(
                    new SelectItem(new NamedObject("first"), "first"),
                    new SelectItem(new NamedObject("second"), "second")
            );
        }
        return selectItems;
    }
}

7) Sample converter

@FacesConverter (value = "namedObjectConverter")
public class NamedObjectConverter implements Converter {
    @Override
    public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
        return new NamedObject(s);
    }

    @Override
    public String getAsString(
            FacesContext facesContext, UIComponent uiComponent, Object o) {
        return o == null ? null : ((NamedObject)o).getName();
    }
}

8) Object that is used

public class NamedObject {
    private String name;

    public NamedObject(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        NamedObject that = (NamedObject) o;

        return name != null ? name.equals(that.name) : that.name == null;
    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (8 by maintainers)

Most upvoted comments

That is completely unrealistic @StevenHachel - you can’t fault on updating your frameworks and then throw your toys when you’re out of date. You fell behind, do the work to catch up. You can’t expect things to work the same they did 5 years or code in the same way you did all those years ago, the technology has changed, quicker now than ever before.

@StevenHachel I understand your frustration but the amount of improvements, security fixes, and bug fixes has been absolutely massive since 6.1 I think over 1200 GitHub tickets have been closed and I know at least 3-4 major security CVE’s. So I highly recommend going to PF8 and reading the Migration Guide.

Yes it will be painful but it will be worth it.

You cant expect that APIs doesn’t change for 10 years. Normally you migrate to 2 other frameworks in this time ;D Check the migration guide, everything is good documented there.

PR submitted can you guys please code review.

I get the same ClassCastException. The failure is introduced by ticket #2862 with commit https://github.com/melloware/primefaces/commit/d95e467070255642be3c9b92dfccd7fdee93322c#diff-e4d3a342df3de892c8fd79acabe27e6bR60.

In SelectOneMenuRenderer#decode the value of a selectItem is set to submittedValue. With a converter this can be every type of class. As far as I understand submittedValue, it must be a String. So later on the ClassCastException is thrown:

Caused by: java.lang.ClassCastException: com.example.XXX cannot be cast to java.lang.String
	at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:318) 
	at org.primefaces.component.selectonemenu.SelectOneMenu.queueEvent(SelectOneMenu.java:318)

in MenuRenderer I am not sure what would be the correct solution for this.

  1. Only set the submittedValue again if the selectItem.value is of type String
  2. Only set the submittedValue again if no Converter is present. Not sure what is happening in the case of having an Integer as value in the selectItem.
  3. ???

Similar problem here. I have a class cast exception stating that java.lang.Integer cannot be cast to java.lang.String. Reverted back to PF 6.1 and it solved the problem.

Have you tried this with the code in trunk for 6.3-SNAPSHOT?