Primefaces picklist. Setter for DualListModel removes source and target

jsf, primefaces

Solution

I had the same problem and it seems that the solution is to impement a custom converter for the entity you use in picklist.

This is how my custom converter looks like:

@ViewScoped
@ManagedBean(name = "vehicleGroupConverter")
public class VehicleGroupConverter implements Converter {

    @ManagedProperty(value = "#{vehiclesBean}")
    private VehiclesBean vehiclesBean;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component,
            String value) {
        long groupId = Long.parseLong(value);
        List<AssetCategory> groups = vehiclesBean.getVehicleGroups();
        for (AssetCategory group : groups) {
            if (group.getCategoryId() == groupId) {
                return group;
            }
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component,
            Object value) {
        return Long.toString(((AssetCategory) value).getCategoryId());
    }

    public void setVehiclesBean(VehiclesBean vehiclesBean) {
        this.vehiclesBean = vehiclesBean;
    }

}

And this is the picklist template part:

<p:pickList id="vehicleGroups" 
        value="#{vehiclesBean.selectedVehicleGroups}" 
        var="group" 
        itemLabel="#{group.name}" 
        itemValue="#{group}"
        converter="#{vehicleGroupConverter}"
        styleClass="pf-panel-grid"
        style="margin-bottom:10px">
    <f:facet name="sourceCaption">#{i18n['label-available-groups']}</f:facet>
    <f:facet name="targetCaption">#{i18n['label-assigned-groups']}</f:facet>
</p:pickList>

Problem

I am having a problem with my picklist. Showing the source and targets works, but when the commandbutton is pressed it calles the setter of the picklist and empties the source and target of the picklist. After that it calls the method connectTags(). What is the reason of this behavior and how could I solve this? ``` <h:form> <p:pickList id="pickList" value="#{employeeEditController.dualListTags}" var="tag" itemLabel="#{tag.value}" itemValue="#{tag}"> <f:facet name="sourceCaption">Available</f:facet> <f:facet name="targetCaption">Connected</f:facet> </p:pickList> <p:commandButton value="Save" actionListener="#{employeeEditController.connectTag()}"/> </h:form> ``` Bean: ``` @Named(value = "employeeEditController") @SessionScoped public class EmployeeEditController implements Serializable, IEditController { private Employee selectedEmployee; private DualListModel<Tags> dualListTags; @Inject private EmployeeFacade employeeFacade; @Inject private CompanyFacade companyFacade; @Inject private TagFacade tagFacade; public void setSelectedEmployee(Employee selectedEmployee) { System.out.println("setSelectedEmployee called. Value: " + selectedEmployee.getFirstName()); this.selectedEmployee = selectedEmployee; this.refreshDualList(); } private void refreshDualList(){ List<Tags> source = (List<Tags>) this.getCompanyTags(); List<Tags> target = (List<Tags>) this.getTags(); System.out.println("refreshDualList called. \nSource: " + source.size() + "Target: " + target.size()); this.dualListTags = new DualListModel<Tags>(source, target); } public Collection<Tags> getTags(){ Collection<Tags> retVal; if(this.selectedEmployee != null){ retVal = this.selectedEmployee.getTags(); if(retVal == null){ retVal = new ArrayList<Tags>(); } } else{ System.out.println("selected emp is null"); retVal = new ArrayList<Tags>(); } return retVal; } public Collection<Tags> getCompanyTags() { Collection<Tags> retVal = new ArrayList<Tags>(); if(this.companyID == null){ String userstr = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser(); this.companyID = this.companyFacade.getCompanyIDByUser(userstr); } retVal = this.tagFacade.getTagsFromCompanyID(companyID); return retVal; } public void save(){ if(this.selectedEmployee != null){ System.out.println("Save called. Value: " + this.selectedEmployee.getFirstName()); this.employeeFacade.edit(this.selectedEmployee); } } public void connectTag() { if(this.dualListTags != null){ System.out.println("connectTag() called.\n" + "source: " + this.dualListTags.getSource().size() + "\ntarget: " + this.dualListTags.getTarget().size()); this.selectedEmployee.setTags((Collection<Tags>)this.dualListTags.getTarget()); this.save(); } } public DualListModel<Tags> getDualListTags() { System.out.println("getDualList called. \nSource :" + this.dualListTags.getSource().size() + "\nTargets: " + this.dualListTags.getTarget().size()); return this.dualListTags; } public void setDualListTags(DualListModel<Tags> dualListTags) { System.out.println("setDualList called. \nSource :" + this.dualListTags.getSource().size() + "\nTargets: " + this.dualListTags.getTarget().size()); this.dualListTags = dualListTags; System.out.println("setDualList called after set. \nSource :" + this.dualListTags.getSource().size() + "\nTargets: " + this.dualListTags.getTarget().size()); } } ```

Original source