JSF String cannot be cast to javax.faces.model.SelectItem

jimmykimmy

Mitglied
Hallo, ich sitze seit 4 Stunden an einem Problem und weiß einfach nicht mehr weiter.

Ich möchte auf einer Seite Checkboxen anzeigen lassen. Das klappt auch wunderbar. Nach dem "abschicken" des Forms, wird eine Funktion "anzeigen" aufgerufen. Diese soll die angekreuzten Checkbox-Werte wiedergeben (also: was wurde angekreuzt).
Ich bekomme allerdings IMMER die Fehlermeldung: java.lang.String cannot be cast to javax.faces.model.SelectItem

Mein Code sieht wie folgt aus:

index.xhtml:
HTML:
<h:selectManyCheckbox id="nase" value="#{controller.selectItems}">
      <f:selectItems value="#{controller.selectItemsList}" />
</h:selectManyCheckbox>

Controller.java
Java:
public class MitarbeiterController implements Serializable {
    private List<SelectItem> selectItemsList = new ArrayList<SelectItem>();
    private List<SelectItem> selectItems = new ArrayList<SelectItem>();

    ....

    public void setSelectItemsList() {
        Raum obj1 = new Raum();
        Raum obj1 = new Raum();
        Raum obj1 = new Raum();
        selectItemsList.add( new SelectItem( obj1 ) );
        selectItemsList.add( new SelectItem( obj2 ) );
        selectItemsList.add( new SelectItem( obj3 ) );
    }

    public List<SelectItem>getSelectItemsList() {
        return selectItemsList;
    }

    public List<SelectItem> getSelectItems() {
        return selectItems;
    }

    public void setSelectItems(List<SelectItem> e) {
        selectItems = e;
    }

    ...

    public void anzeigen() {
        // die 3 Varianten bringen alle den selben Fehler!
        String str = getSelectItems().get(0).getLabel();  // var 1
        Raum str = (Raum) getSelectItems().get(0).getValue();  // var 2
        String str = getSelectItems().get(0).getValue().toString();  // var 3
        System.out.println("getSelectItems(): " + str);
        // System.out.println( getSelectItems().get(0) ) ruft die toString Methode meines Objekts korrekt auf. Die Daten liegen also korrekt in "selectItems" vor.
    }
}

ich weiß einfach nicht mehr weiter .... :-(
 
Zuletzt bearbeitet von einem Moderator:
Von Convertern habe ich auf meiner Suche auch schon etwas gelesen.
Kannst du mir da genauer erklären, wie man da vorgeht? Oder ist das eine größere Aktion?
 
Hmm ich habe nun mal einen Converter geschrieben, aber wie greift der? Wie wende ich ihn an? Sorry, aber weiß derzeit absolut nicht, was ich machen muss, daher bin ich bei deinem Link auch noch etwas überfragt :-/

Wieso kann man denn nicht stinknormal den Wert einer Checkbox auslesen? :-(
 
Das ist Konfigurationsaufgabe.
Deine WEB-INF/faces-config.xml müsste so starten:
[XML]<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<converter>
<converter-id>stringConverter</converter-id>
<converter-class>de.deinunternehmen.converter.StringConverter</converter-class>
</converter> ...[/XML]

Deine Klasse StringConverter leitet dann von "javax.faces.convert.Converter" ab und implementiert die Methoden.




Einfach auslesen? JSF ist die Weiterentwicklung von "Einfach". Bei Betrachtung im professionellen Umfeld wirst du die Vorzüge zu schätzen wissen.
 
Zuletzt bearbeitet:
Bei mir existierte noch keine "faces-config.xml"-Datei, daher habe ich sie mit folgendem Inhalt angelegt

[XML]<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<converter>
<converter-id>RaumConverter</converter-id>
<converter-class>Converter.Raumconverter</converter-class>
</converter>
</faces-config>[/XML]

Danach bekam ich beim starten nur eine leere weiße Seite im Browser zu sehen.

Ist es korrekt, dass ich die "selectItems" um den Converter erweitere?
HTML:
<f:selectItems value="#{mitarbeitercontroller.selectItemsList}" var="item" itemValue="#{item.id}">
                    <f:converter converterId="Converter.RaumConverter" />
                </f:selectItems>
 
Versuch mal die SelectItems mit dem dazugehörigen Constructor anzulegen:
Java:
SelectItem item = new SelectItem(String key, String description);
 
Ich bin ein Stückchen weiter. Ich habe folgenden Converter geschrieben:
Java:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import Entities.Raum;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

@FacesConverter("Converter.RaumConverter")
public class RaumConverter implements Converter {

    public Object getAsObject(FacesContext ctx, UIComponent uiComponent, String value) {
        Raum raum = new Raum();
        raum.setId(Integer.valueOf(getProperty(value, "id")));
        raum.setRoomName(getProperty(value, "roomName"));
        raum.setBuildingName(getProperty(value, "buildingName"));
        System.out.println("Converter-> Raum: " + raum);
        System.out.println("Converter-> value: " + value);
        return raum;
    }

    private String getProperty(String source, String propName) {
        int idIndex = source.indexOf(propName + "=") + propName.length() + 1;
        int commaIndex = source.indexOf(",", idIndex);
        if (commaIndex < 0) {
            commaIndex = source.indexOf("]");
        }
        //System.out.println(idIndex);
        //System.out.println(commaIndex);
        //System.out.println("getProperty(): " + source.substring(idIndex, commaIndex));
        return source.substring(idIndex, commaIndex);
    }

    public String getAsString(FacesContext ctx, UIComponent uiComponent, Object value) {
        if (!(value instanceof Raum)) {
            throw new ConverterException();
        }
        Raum raum = (Raum) value;
        StringBuffer stringValue = new StringBuffer("[id=");
        stringValue.append(raum.getId());
        stringValue.append(",roomName=");
        stringValue.append(raum.getRoomName());
        stringValue.append(",buildingName=");
        stringValue.append(raum.getBuildingName());
        stringValue.append("]");
        System.out.println("getAsString(): " + stringValue.toString());
        return stringValue.toString();
    }
}

und ihn der der xhtml-Datei so eingebunden:
HTML:
<h:selectManyCheckbox id="nase" converter="Converter.RaumConverter" value="#{controller.selectItems}">
                <f:selectItems value="#{controller.selectItemsList}" var="item" itemValue="#{item}" />
            </h:selectManyCheckbox>

Wenn ich nun auf "ABSCHICKEN" drücke, wird das Formular jedoch nicht abgeschickt, da eine Meldung unterhalb meines Formulars erscheint:

startseite:nase: Validierungs-Fehler: Wert nicht gültig.

Wieso Validiert er da nun falsch? Die System.out.println()-Befehle geben mir korrekte Daten aus, daher gehe ich davon aus, dass ich innerhalb der Converter-Funktionen korrekt arbeite ...

Ich habe irgendwo gelesen, dass "irgendwo eine equals-Methode fehlt". Ich weißt leider nicht genau, was damit gemeint ist.
 
Hab herausgefunden, dass ich die Methode "equals" in meiner Raum-Klasse überschreiben muss, damit nicht mehr städnig "false" geworfen wird. Nun wird das Formular abgeschickt, aber ich bekomme wieder einen Fehler:
Diesmal kann er "Raum" nicht nach "ItemSelect" konvertieren.
Ich flippe bald aus. Ich möchte doch einfach nur die angehakten Checkboxen auswerten :-(
 
Hi,

schau dir das Bsp an (wichtig equals-Methode überschreiben wird in UIComponent aufgerufen):

The BalusC Code: Objects in h:selectOneMenu


In Endeffekt müßtest du die Liste so befühlen :

Java:
new SelectItem(raum.getId(),raum);

in der Methode:

Java:
getAsString(..,...,Obect o){
return ((Raum)o).getRoomName();

und im

Java:
getAsObject(...,...,String value){
long id = Long.valueOf(value);

// hier mit der Id das entsprechende Raum Objekt laden
// entweder aus einer DAO-Klasse oder aus einer ManagedBean, die die Liste hält

// fertig
return raum;
}

Eigentlich verzichtet man drauf Objekte in SelectItems zu packen besser wäre

Java:
new SelectItem(raum.getId(),raum.getRoomName());

und später in der entsprechenden Action-Methode den ausgewählten Raum über id laden.

Grüße
 
Danke!
Ich habe es nun ohne Objekte gemacht und nun läuft es.
Dachte es wäre schöner, wenn man das ganze Objekt zur Verfügung hat, aber wenn die ID reicht und es auch legitim ist, über diese ID später nochmal ne Abfrage zu starten, dann umso besser 🙂
 

Zurück
Oben