Błąd weryfikacji: wartość jest nieprawidłowa

80

Mam problem z ap: selectOneMenu, bez względu na to, co zrobię, nie mogę zmusić JSF do wywołania ustawiacza na encji JPA. Walidacja JSF kończy się niepowodzeniem z tą wiadomością:

formularz: lokalizacja: Błąd walidacji: Wartość jest nieprawidłowa

Mam to działające na kilku innych klasach tego samego typu (tj. Dołączam do zajęć przy stole), ale nie mogę sprawić, by ta działała przez całe życie.

Jeśli ktoś może rzucić kilka wskazówek dotyczących rozwiązywania problemów / debugowania tego rodzaju problemów, byłby bardzo wdzięczny.

Korzystając z instrukcji dziennika, zweryfikowałem następujące kwestie:

  1. ConveterWraca poprawne, niż nullwartości.
  2. W moich podmiotach JPA nie ma funkcji Bean Validation.
  3. Rozgrywający setLocation(Location location)nigdy nie jest wywoływany.

To najprostszy przykład, jaki mogę zrobić i po prostu nie zadziała:

<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>

Przetwornik:

@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());
    }    
}

Wyjście konsoli:

// 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] 
klonq
źródło

Odpowiedzi:

143

Weryfikacja kończy się niepowodzeniem i wyświetlany jest komunikat „formularz: lokalizacja: Błąd weryfikacji: wartość jest nieprawidłowa”

Ten błąd sprowadza się do tego, że wybrany element nie pasuje do żadnej z dostępnych wartości wybranych elementów określonych przez którykolwiek zagnieżdżony <f:selectItem(s)> znacznik podczas przetwarzania żądania przesłania formularza.

W ramach zabezpieczenia przed naruszeniem / zhakowaniem żądań JSF powtórzy wszystkie dostępne wybrane wartości pozycji i sprawdzi, czy selectedItem.equals(availableItem) zwraca trueprzynajmniej jedną dostępną wartość pozycji. Jeśli żadna z wartości pozycji nie pasuje, otrzymasz dokładnie ten błąd weryfikacji.

Ten proces znajduje się pod okładkami zasadniczo jak poniżej, gdzie bean.getAvailableItems()fikcyjnie przedstawia całą listę dostępnych wybranych elementów, zgodnie z definicją <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");
}

Tak więc, w oparciu o powyższą logikę, ten problem może logicznie mieć co najmniej następujące przyczyny:

  1. Wybranego elementu brakuje na liście dostępnych elementów.
  2. equals()Metoda klasy reprezentujące wybranego elementu brakuje lub jest uszkodzony.
  3. Jeśli w grę Converterwchodzi zwyczaj , zwrócił on niewłaściwy obiekt w formacie getAsObject(). Może nawet null.

Aby to rozwiązać:

  1. Upewnij się, że dokładnie ta sama lista została zachowana podczas kolejnego żądania, szczególnie w przypadku wielu menu kaskadowych. Dokonywanie fasoli @ViewScopedzamiast @RequestScopedpowinna go naprawić w większości przypadków. Upewnij się również, że nie wykonujesz logiki biznesowej w metodzie pobierającej <f:selectItem(s)>, ale zamiast tego w @PostConstructmetodzie zdarzenia akcji (detektor). Jeśli polegasz na określonych parametrach żądania, musisz jawnie przechowywać je w @ViewScopedziarnie lub przekazywać je ponownie w kolejnych żądaniach, np <f:param>. Zobacz także Jak wybrać odpowiednią lunetę do fasoli?
  2. Upewnij się, że equals()metoda została zaimplementowana prawidłowo. To już jest zrobione tuż przy standardowych typów, takich jak Java java.lang.String, java.lang.Numberitp, ale niekoniecznie na niestandardowych obiektów / fasola / udziałów w jednostkach. Zobacz także Właściwy sposób realizacji umowy równa się . Jeśli już używasz String, upewnij się, że kodowanie znaków żądania jest skonfigurowane prawidłowo. Jeśli zawiera znaki specjalne, a JSF jest skonfigurowany do renderowania danych wyjściowych jako UTF-8, ale interpretuje dane wejściowe jako np. ISO-8859-1, to zakończy się niepowodzeniem. Zobacz także ao Dane wejściowe Unicode pobrane przez PrimeFaces zostały uszkodzone .
  3. Debuguj / rejestruj działania niestandardowe Converteri odpowiednio je napraw. Aby uzyskać wskazówki, zobacz także ustawienie wartości błędu konwersji dla 'null Converter'. Jeśli używasz java.util.Datejako dostępnych elementów z <f:convertDateTime>, upewnij się, że nie zapomnisz części wzorca w pełnym wymiarze godzin. Zobacz także błąd „Błąd sprawdzania poprawności: wartość jest nieprawidłowa” z f: datetimeConverter .

Zobacz też:


Jeśli ktoś może rzucić kilka wskazówek dotyczących rozwiązywania problemów / debugowania tego rodzaju problemów, byłby bardzo wdzięczny.

Po prostu zadaj tutaj jasne i konkretne pytanie. Nie zadawaj zbyt szerokich pytań;)

BalusC
źródło
@BalusC: Gdzie dokładnie jest to w kodzie mojarra, że ​​to equalssprawdzenie ma miejsce. Moja sytuacja jest nieco złożona. Tworzę własny niestandardowy komponent, który pozwala użytkownikowi mieć złożony układ radia. Działa dobrze, jeśli mam tylko jedną grupę radiową (f: selectItems tuż pod moim niestandardowym komponentem). Jednak w miarę jak układ staje się bardziej złożony (wiele grup radiowych, każda ma swoje własne f: selectItems, ale wszystkie mają ten sam wybór), muszę mieć f: selectItems w interfejsie ui: repeat, a następnie ui: repeat jest pod moim niestandardowym komponentem. Wtedy natknąłem się na ten problem. Chcę zobaczyć kod mojarra, który to obsługuje
Thang Pham
Również mój f: selectItems jest typu String, więc jestem pewien, że nie jest to problem z konwersją, myślę, że jest to przyczyna, ponieważ lista f: selectItems nie istnieje podczas fazy walidacji.
Thang Pham
Czy możesz wyjaśnić, jak używać f: param do wysyłania stanu do zarządzanego komponentu bean, aby mógł on odtworzyć „stan początkowy” ??? Dzięki.
Agustí Sánchez
1
Mając podobny błąd. Używam SelectItemsConverter i ten składnik znajduje się wewnątrz wyłączonego zestawu pól - więc jest również wyłączony. Czy to znane zachowanie?
Gilberto
Jeśli używasz wyliczenia dla elementów do wyświetlenia, a fasola zapasowa ma typ String do ustawiania wartości w ziarnie i nie używa żadnych konwerterów, otrzymasz ten sam błąd. W ten sposób znalazłem się tutaj.
Philip Puthenvila,
2

W moim przypadku zapomniałem zaimplementować poprawnych metod get / set. Stało się tak, ponieważ wraz z rozwojem zmieniłem wiele atrybutów.

Bez odpowiedniej metody pobierania JSF nie może odzyskać wybranego elementu i dzieje się tak, jak powiedział BalusC w punkcie 1 swojej odpowiedzi:

1. Wybranego elementu brakuje na liście dostępnych elementów. Może się tak zdarzyć, jeśli lista dostępnych elementów jest obsługiwana przez komponent bean o zasięgu żądania, który nie jest poprawnie ponownie inicjowany przy kolejnym żądaniu lub nieprawidłowo wykonuje zadanie biznesowe w ramach metody pobierającej, co powoduje, że w jakiś sposób zwraca inną listę.

Henrique Liberato
źródło
1

Może to być problem z konwerterem lub problem z DTO. Spróbuj rozwiązać ten problem, dodając metody hashCode () i equals () w swoim obiekcie DTO; W powyższym scenariuszu można wygenerować te metody w ramach klasy obiektu Location, które wskazują tutaj jako „DTO”.

Przykład:

@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;
}
  • Należy pamiętać, że powyższy przykład dotyczy identyfikatora typu „long”.
Rizla Shareefdeen
źródło
Jak stwierdzono w punkcie 2 w zaakceptowanej i bardzo pozytywnej odpowiedzi
Kukeltje