Primefaces selectOneMenu converter called but not

2019-07-19 23:08发布

问题:

I've looked at the other questions this and this, etc, the problem is that my convert gets called but the values of selectOneMenu doesn't change. My entity class is generated, and has equals as well as hashCode and I would like not to change anything in it - if it gets regenerated then all changes will be lost (The work around is to change toString of the entity class).

The XHTML code snipped:

<p:selectOneMenu id="defid" 
                 value="#{abcController.selected.defid}"
                 converter="defConverter">

The Converter:

@FacesConverter("defConverter")
public class DefConverter implements Converter
{
    private static final Logger LOG = Logger.getLogger(DefConverter.class.getName());
    @EJB
    private DefFacade defFacade;

    @Override
    public Object getAsObject(FacesContext fc, UIComponent uic, String string)
    {
        LOG.info("getAsObject: " + string);
        try
        {
            return defFacade.findWithNFieldsWithValue("name", string, "=").get(0);
        }
        catch (Exception ex)
        {
            LOG.log(Level.SEVERE, "Error while fetching Def for " + string, ex);
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext fc, UIComponent uic, Object obj)
    {
        LOG.info("getAsString obj class: " + obj.getClass().getName());
        if(obj instanceof Def)
        {
            Def def = (Def)obj;
            LOG.info("getAsString def name: " + def.getName());
            return def.getName();
        }
        else
        {
            StringBuilder sbError = new StringBuilder("The object of class ");
            sbError.append(obj.getClass().getName()).append(" is not of Def");
            throw new ClassCastException(sbError.toString());
        }
    }
}

The entity class snipped (this is generated):

...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "defid")
private Long defid;
...

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

@Override
public boolean equals(Object object)
{
    // TODO: Warning - this method won't work in the case the id fields are not set
    if (!(object instanceof Def))
    {
        return false;
    }
    Def other = (Def) object;
    if ((this.defid == null && other.defid != null) || (this.defid != null && !this.defid.equals(other.defid)))
    {
        return false;
    }
    return true;
}

When the page loads, I can see the log statements as follow:

getAsString obj class: com.xyz.Def
getAsString def name: Name 1
getAsString obj class: com.xyz.Def
getAsString def name: Name 2
getAsString obj class: com.xyz.Def
getAsString def name: Name 3

Thus the converter gets called and returns the correct values but on the page it is still com.xyz.Def[ defid=1 ] (Drop down and normal)

回答1:

The converter seems to be working, but you didn't post the whole <p:selectOneMenu> code, in particular <f:selectItems>. It should look something like this

<p:selectOneMenu id="defid" 
                 value="#{abcController.selected.defid}"
                 converter="defConverter">
    <f:selectItems value="#{abcController.defs}" var="def"
                       itemLabel="#{def.name}" itemValue="#{def.defId}" />
</p:selectOneMenu>

itemLabel is responsible for printing displayed values.



回答2:

Try the following code

<p:selectOneMenu id="defid" value="#{abcController.selected.def}"
             converter="defConverter">
   <f:selectItems value="#{abcController.defs}" var="def" 
        itemValue="#{def}" itemLabel="#{def.name}" />       
</p:selectOneMenu>

Converter is used to convert between a complex Java object and a String representation. For this you need to specify the whole def object as item value instead. You should also ensure that #{abcController.selected.def} refers to a def property, not some Long property representing the def ID.