web-dev-qa-db-fra.com

Erreur de validation: la valeur n'est pas valide

J'ai un problème avec un p: selectOneMenu, peu importe ce que je fais, je ne peux pas demander à JSF d'appeler le paramètre de configuration sur l'entité JPA. La validation JSF échoue avec ce message:

formulaire: emplacement: erreur de validation: valeur non valide

J'ai ce travail sur plusieurs autres classes du même type (c'est-à-dire, rejoindre des classes de table) mais je ne peux pas pour la vie de celui-ci faire fonctionner celle-ci.

Si quelqu'un peut donner quelques conseils de dépannage/débogage pour ce type de problème, il serait grandement apprécié.

À l'aide des instructions de journal, j'ai vérifié les éléments suivants:

  1. Conveter renvoie des valeurs correctes et non null.
  2. Je n'ai pas de validation de bean dans mes entités JPA.
  3. Le poseur setLocation(Location location) n'est jamais appelé.

C'est l'exemple le plus simple que je puisse faire et cela ne fonctionnera tout simplement pas:

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

Convertisseur:

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

Sortie de la console:

// 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] 
73
klonq

La validation échoue avec le message "formulaire: emplacement: erreur de validation: la valeur n'est pas valide"

Cette erreur se résume à ce que l'élément sélectionné ne correspond à aucune des valeurs d'élément de sélection disponibles spécifiées par une balise imbriquée <f:selectItem(s)> lors du traitement de la demande d'envoi de formulaire.

Dans le cadre de la protection contre les demandes altérées/piratées, JSF réitère toutes les valeurs d'élément de sélection disponibles et teste si selectedItem.equals(availableItem) renvoie true pour au moins une valeur d'élément disponible. Si aucune valeur d'élément ne correspond, vous obtiendrez exactement cette erreur de validation.

Ce processus est fondamentalement identique à celui décrit ci-dessous, dans lequel bean.getAvailableItems() représente de manière fictive la liste complète des éléments de sélection disponibles définis par <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");
}

Donc, basé sur la logique ci-dessus, ce problème peut logiquement avoir au moins les causes suivantes:

  1. L'élément sélectionné est manquant dans la liste des éléments disponibles.
  2. La méthode equals() de la classe représentant l'élément sélectionné est manquante ou endommagée.
  3. Si un Converter personnalisé est impliqué, il a renvoyé le mauvais objet dans getAsObject(). C'est peut-être même null.

Pour le résoudre:

  1. Assurez-vous que la même liste a été préservée lors de la requête suivante, en particulier dans le cas de plusieurs menus en cascade. Faire le bean @ViewScoped Au lieu de @RequestScoped Devrait résoudre le problème dans la plupart des cas. Assurez-vous également que vous n'effectuez pas la logique métier dans la méthode getter de <f:selectItem(s)>, mais dans @PostConstruct Ou dans une méthode d'événement d'action (écouteur). Si vous vous basez sur des paramètres de requête spécifiques, vous devez les stocker explicitement dans le bean @ViewScoped Ou les retransmettre lors de demandes ultérieures, par exemple. <f:param>. Voir aussi Comment choisir la bonne portée?
  2. Assurez-vous que la méthode equals() est correctement implémentée. Ceci est déjà fait directement sur les types standard Java tels que Java.lang.String, Java.lang.Number, Etc., mais pas nécessairement sur les objets/beans/entités personnalisés. Voir aussi - bonne façon de mettre en œuvre un contrat égal . Si vous utilisez déjà String, assurez-vous que le codage de caractères de la requête est correctement configuré. S'il contient des caractères spéciaux et que JSF est configuré pour rendre le une sortie au format UTF-8 mais interprétez l’entrée comme ISO-8859-1, elle échouera (voir aussi ao l’entrée Unicode récupérée via les composants d’entrée PrimeFaces est corrompue .
  3. Déboguez/enregistrez les actions de votre Converter personnalisé et corrigez-le en conséquence. Pour des instructions, voir aussi Valeur du paramètre Erreur de conversion pour 'Convertisseur null' Si vous utilisez Java.util.Date Comme éléments disponibles avec <f:convertDateTime>, Assurez-vous de ne pas le faire. t oublier la partie à temps plein dans le modèle. Voir aussi erreur "Erreur de validation: la valeur n'est pas valide" de f: datetimeConverter .

Voir également:


Si quelqu'un pouvait donner quelques conseils de dépannage/débogage pour ce genre de problème, il serait grandement apprécié.

Posez simplement une question claire et concrète ici. Ne posez pas de questions trop générales;)

129
BalusC

Dans mon cas, j'ai oublié d'implémenter une méthode get/set correcte. C'est arrivé parce que j'ai changé beaucoup d'attributs au cours du développement.

Sans une méthode get appropriée, JSF ne peut pas récupérer l’élément sélectionné et il arrive ce que BalusC a dit au point 1 de sa réponse:

1 . L'élément sélectionné est manquant dans la liste des éléments disponibles. Cela peut se produire si la liste des éléments disponibles est servie par un bean périmé de requête qui n'est pas correctement réinitialisé lors d'une requête ultérieure, ou qui exécute de manière incorrecte le travail dans une méthode de lecture, ce qui entraîne le renvoi d'une liste différente.

2
Henrique Liberato

Cela peut être un problème de convertisseur ou bien un problème de DTO. Essayez de résoudre ce problème en ajoutant les méthodes hashCode () et equals () dans votre objet DTO; Dans le scénario ci-dessus, vous pouvez générer ces méthodes dans la classe d'objets Location qui indiquent ici le 'DTO'.

Exemple:

@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;
}
  • Veuillez noter que l'exemple ci-dessus concerne un 'id' de type 'long'.
1
Rizla Shareefdeen