1

Final solution of the problem for getting the converter, equals and JSF code to work.

The Player is a Player bean with a few properties. The service access the Player and writes player info to the database (besides the point :)

<h:selectOneListbox size="1" value="#{player}" 
                converter="playerConverter" id="playerList">
            <f:selectItems value="#{servicePlayer.allPlayers}"
             var="n"
             itemValue="#{n}"
             itemLabel="#{n.combinedName}"
             itemLabelEscaped="true"/>
            </h:selectOneListbox>

In ServicePlayer

public List<Player> getAllPlayers() {

        if (factory == null) {
            factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        }

        EntityManager em = factory.createEntityManager();
        Query q = em.createQuery("select t from Player t");

        List<Player> players = q.getResultList();

.... 

@FacesConverter(value = "playerConverter")
public class PlayerConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null) {
            return null;
        }

        long idValue;
        try {
            idValue = Long.parseLong(value);
        }
        catch (NumberFormatException ex)
        {
            return null;
        }

        ServicePlayer servicePlayer = context.getApplication()
                .evaluateExpressionGet(context, "#{servicePlayer}",
                        ServicePlayer.class);
        Player player = servicePlayer.getPlayerByID(idValue);
        return player;

    }

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

}

In Player

@Override
    public boolean equals(Object other) {
        return (id != null && other != null && getClass() == other.getClass())
             ? id.equals(((Player) other).getId())
             : (other == this);
    }

    @Override
    public int hashCode() {
        return (id != null) 
             ? (getClass().hashCode() + id.hashCode()) 
             : super.hashCode();
    }
user2130951
  • 2,601
  • 4
  • 31
  • 58
  • 1
    possible duplicate of [Best way to "switch" bean on selection in JSF](http://stackoverflow.com/questions/20629975/best-way-to-switch-bean-on-selection-in-jsf) – Aritz Dec 18 '13 at 09:59

2 Answers2

2

in getAsString you are returning a String object, and in getAsObject you are trying to parse the value as Long: idValue = Long.parseLong(value); which does not make any sense.

You should return the proper id in getAsString so you can get it in getAsObject.

Updated

E.g. Your getAsString method should look like :

public String getAsString(FacesContext facesContext, UIComponent component, Object value) {
    if (value == null || value.equals("")) {
        return "";
    }
    else {
        return String.valueOf(((ServicePlayer) value).getId());
    }
}
Ioan
  • 5,152
  • 3
  • 31
  • 50
1

It should be like this.

       <f:selectItems value="#{servicePlayer.allPlayers}"
             var="n"
             itemValue="#{n}"
             itemLabel="#{n.combinedName}"
             itemLabelEscaped="true"/>
        </h:selectOneListbox>

The itemValue should be the player object (n), NOT n.stringID, since the value of the h:selectOneListbox is a player object.

getAsObject

@Override
public Object getAsObject(FacesContext context, 
                          UIComponent component, String value) {
    if (value == null) {
        return null;
    }

    long idValue;
    try {
        idValue = Long.parseLong(value);
    }
    catch (NumberFormatException ex)
    {
        return null;
    }

    ServicePlayer servicePlayer = context.getApplication()
            .evaluateExpressionGet(context, "#{servicePlayer}",
                    ServicePlayer.class);
    Player player = servicePlayer.getPlayerByID(idValue);
    return player;

}

getAsString

@Override
public String getAsString(FacesContext context, 
                              UIComponent component, Object value) {
    if (value == null || value.equals("")) {
        return "";
    } else {
        return String.valueOf(((Player)value).getStringID()); 
                //or what ever the id is
    }
}

EDIT: Please note that the Player MUST implement the equals and the hashcode methods.

See Also:

Hope this helps.

Community
  • 1
  • 1
Hatem Alimam
  • 9,968
  • 4
  • 44
  • 56
  • Thanks, this helps clearing some problems. However I am getting sourceId=j_idt12:playerList[severity=(ERROR 2), summary=(j_idt12:playerList: Validation Error: Value is not valid), detail=(j_idt12:playerList: Validation Error: Value is not valid)] which means I can call the – user2130951 Dec 18 '13 at 09:26
  • This means that the Player does NOT implement the equals and the hashcode. please consider implementing them. – Hatem Alimam Dec 18 '13 at 09:32
  • More on equals ... http://stackoverflow.com/questions/9069379/validation-error-value-is-not-valid/9069660#9069660 – Hatem Alimam Dec 18 '13 at 09:41