Validierungsfehler: Wert ist ungültig


80

Ich habe ein Problem mit ap: selectOneMenu, egal was ich tue, ich kann JSF nicht dazu bringen, den Setter auf der JPA-Entität aufzurufen. Die JSF-Validierung schlägt mit dieser Meldung fehl:

form: location: Validation Error: Wert ist ungültig

Ich habe diese Arbeit an mehreren anderen Klassen des gleichen Typs (dh an Tabellenklassen teilnehmen), kann diese aber für mein ganzes Leben nicht zum Laufen bringen.

Wenn jemand Tipps zur Fehlerbehebung / zum Debuggen für diese Art von Problem geben kann, wäre er sehr dankbar.

Mit Hilfe von Protokollanweisungen habe ich Folgendes überprüft:

  1. Das Convetergibt korrekte, nicht nullWerte zurück.
  2. Ich habe keine Bean-Validierung in meinen JPA-Entitäten.
  3. Der Setter setLocation(Location location)wird nie aufgerufen.

Dies ist das einfachste Beispiel, das ich machen kann, und es wird einfach nicht funktionieren:

<h:body>
    <h:form id="form">
        <p:messages id="messages" autoUpdate="true" />
        <p:selectOneMenu id="location" value="#{locationStockList.selected.location}" converter="locationConverter">
            <p:ajax event="change" update=":form:lblLocation"/>
            <f:selectItems value="#{locationStockList.locationSelection}"/>
        </p:selectOneMenu>
    </h:form>
</h:body>

Konverter:

@FacesConverter(forClass=Location.class, value="locationConverter")
public class LocationConverter implements Converter, Serializable {
    private static final Logger logger = Logger.getLogger(LocationConverter.class.getName());

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value.isEmpty())
            return null;
        try {
            Long id = Long.parseLong(value);
            Location location = ((LocationManagedBean) context.getApplication().getELResolver().getValue(context.getELContext(), null, "location")).find(id);
            logger.log(Level.SEVERE, "Converted {0} to {1}" , new Object[] {value, location});
            return location;
        } catch (NumberFormatException e) {
            return new Location();
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null || value.toString().isEmpty() || !(value instanceof Location))
            return "";
        return String.valueOf(((Location) value).getId());
    }    
}

Konsolenausgabe:

// Getter method
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 
// Session Bean
INFO: Finding ejb.locations.Location with id=3 
// Session Bean
INFO: ### Returning : ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Converter
SEVERE: Converted 3 to ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Getter method -> Where did my selected Location go ??
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 

Antworten:


143

Die Validierung schlägt mit der Meldung "Formular: Speicherort: Validierungsfehler: Wert ist ungültig" fehl.

Dieser Fehler führt dazu, dass das ausgewählte Element keinem der verfügbaren Werte für ausgewählte Elemente entspricht, die von einem verschachtelten <f:selectItem(s)> Tag während der Verarbeitung der Formularübermittlungsanforderung angegeben wurden.

Im Rahmen des Schutzes vor Manipulation / gehackt Anfragen werden JSF alle verfügbaren Auswahlelementwerte wiederholen über und testen , ob selectedItem.equals(availableItem) Erträge truefür mindestens einen verfügbaren Elementwert. Wenn kein Elementwert übereinstimmt, wird genau dieser Validierungsfehler angezeigt.

Dieser Prozess wird im Wesentlichen wie folgt behandelt, wobei bean.getAvailableItems()die gesamte Liste der verfügbaren ausgewählten Elemente fiktiv dargestellt wird, wie definiert durch <f:selectItem(s)>:

String submittedValue = request.getParameter(component.getClientId());
Converter converter = component.getConverter();
Object selectedItem = (converter != null) ? converter.getAsObject(context, component, submittedValue) : submittedValue;

boolean valid = false;

for (Object availableItem : bean.getAvailableItems()) {
    if (selectedItem.equals(availableItem)) {
        valid = true;
        break;
    }
}

if (!valid) {
    throw new ValidatorException("Validation Error: Value is not valid");
}

Basierend auf der obigen Logik kann dieses Problem logischerweise mindestens die folgenden Ursachen haben:

  1. Das ausgewählte Element fehlt in der Liste der verfügbaren Elemente.
  2. Die equals()Methode der Klasse, die das ausgewählte Element darstellt, fehlt oder ist fehlerhaft.
  3. Wenn ein Benutzer Converterbetroffen ist, hat er das falsche Objekt zurückgegeben getAsObject(). Vielleicht ist es sogar null.

Um es zu lösen:

  1. Stellen Sie sicher, dass bei der nachfolgenden Anforderung genau dieselbe Liste beibehalten wird, insbesondere bei mehreren kaskadierenden Menüs. Die Herstellung der Bohne @ViewScopedanstelle @RequestScopedsollte in den meisten Fällen behoben werden. Stellen Sie außerdem sicher, dass Sie die Geschäftslogik nicht in der Getter-Methode von <f:selectItem(s)>, sondern in der Methode @PostConstructoder einem Aktionsereignis (Listener) ausführen . Wenn Sie sich auf bestimmte Anforderungsparameter verlassen, müssen Sie diese explizit in der @ViewScopedBean speichern oder bei nachfolgenden Anforderungen erneut übergeben, z <f:param>. Siehe auch So wählen Sie den richtigen Bean-Bereich aus.
  2. Stellen Sie sicher, dass die equals()Methode richtig implementiert ist. Dies ist bereits direkt auf Standard - Java - Typen gemacht wie java.lang.String, java.lang.Numberusw, aber nicht unbedingt auf benutzerdefinierte Objekte / Bohnen / entites. Siehe auch Richtiger Weg zur Implementierung eines gleichwertigen Vertrags . Falls Sie bereits verwenden String, stellen Sie sicher, dass die Anforderungszeichencodierung richtig konfiguriert ist. Wenn es Sonderzeichen enthält und JSF so konfiguriert ist, dass die Ausgabe als UTF-8 gerendert wird, die Eingabe jedoch als z. B. ISO-8859-1 interpretiert wird, schlägt dies fehl. Siehe auch ua Unicode-Eingaben, die über PrimeFaces-Eingabekomponenten abgerufen werden, werden beschädigt .
  3. Debuggen / protokollieren Sie die Aktionen Ihrer benutzerdefinierten Converterund korrigieren Sie sie entsprechend. Richtlinien finden Sie auch unter Einstellungswert für Konvertierungsfehler für 'Null-Konverter'. Wenn Sie java.util.Dateals verfügbare Elemente mit verwenden <f:convertDateTime>, stellen Sie sicher, dass Sie den Vollzeit-Teil im Muster nicht vergessen. Siehe auch Fehler "Validierungsfehler: Wert ist ungültig" von f: datetimeConverter .

Siehe auch:


Wenn jemand Tipps zur Fehlerbehebung / zum Debuggen für diese Art von Problem geben kann, wäre er sehr dankbar.

Stellen Sie hier einfach eine klare und konkrete Frage. Stelle keine zu breiten Fragen;)


@BalusC: Wo genau steht es im Mojarra-Code, dass diese equalsPrüfung stattfindet ? Meine Situation ist etwas komplex. Ich erstelle meine eigene benutzerdefinierte Komponente, die es dem Benutzer ermöglicht, ein komplexes Radio-Layout zu haben. Es funktioniert gut, wenn ich nur eine Funkgruppe habe (f: selectItems direkt unter meiner benutzerdefinierten Komponente). Wenn das Layout jedoch komplexer wird (mehrere Funkgruppen, jede hat ihre eigenen f: selectItems, aber alle haben dieselbe Auswahl), muss ich f: selectItems in ui: repeat haben, dann befindet sich die ui: repeat unter meiner benutzerdefinierten Komponente. Ich bin dann auf dieses Problem gestoßen. Ich möchte den Mojarra-Code sehen, der damit umgeht
Thang Pham

Außerdem ist mein f: selectItems vom Typ String, daher bin ich sicher, dass dies kein Konvertierungsproblem ist. Ich denke, dies liegt daran, dass die Liste der f: selectItems während der Validierungsphase nicht vorhanden ist.
Thang Pham

Können Sie erläutern, wie Sie mit f: param den Status an die verwaltete Bean senden, damit dieser den "Anfangsstatus" wiederherstellen kann? Vielen Dank.
Agustí Sánchez

1
Einen ähnlichen Fehler haben. Ich verwende den SelectItemsConverter und diese Komponente befindet sich in einem deaktivierten Feldsatz - daher ist sie auch deaktiviert. Ist es ein bekanntes Verhalten?
Gilberto

Wenn Sie enum für die anzuzeigenden Elemente verwenden und Ihre Backing-Bean den Typ String zum Festlegen des Werts in der Bean hat und keine Konverter verwendet, wird der gleiche Fehler angezeigt. So bin ich hier gelandet.
Philip Puthenvila

2

In meinem Fall habe ich vergessen, eine korrekte get / set-Methode zu implementieren. Es ist passiert, weil ich im Laufe der Entwicklung viele Attribute geändert habe.

Ohne eine geeignete Get-Methode kann JSF Ihren ausgewählten Artikel nicht wiederherstellen, und es passiert, was BalusC unter Punkt 1 seiner Antwort gesagt hat:

1. Das ausgewählte Element fehlt in der Liste der verfügbaren Elemente. Dies kann passieren, wenn die Liste der verfügbaren Elemente von einer Bean mit Anforderungsbereich bereitgestellt wird, die bei einer nachfolgenden Anforderung nicht ordnungsgemäß neu initialisiert wird, oder wenn die Geschäftsaufgabe innerhalb einer Getter-Methode falsch ausgeführt wird, wodurch eine andere Liste auf irgendeine Weise zurückgegeben wird.


1

Dies kann ein Konverterproblem oder ein DTO-Problem sein. Versuchen Sie dies zu lösen, indem Sie Ihrem Objekt DTO die Methoden hashCode () und equals () hinzufügen. Im obigen Szenario können Sie diese Methoden innerhalb der Location-Objektklasse generieren, die hier als 'DTO' angegeben sind.

Beispiel:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (id ^ (id >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Location other = (Location) obj;
    if (id != other.id)
        return false;
    return true;
}
  • Bitte beachten Sie, dass das obige Beispiel für eine 'ID' vom Typ 'long' gilt.

Wie in # 2 in der akzeptierten und hoch bewerteten Antwort angegeben
Kukeltje
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.