83 votes

Erreur de validation : La valeur n'est pas valide

J'ai un problème avec un p:selectOneMenu, quoi que je fasse, je n'arrive pas à faire en sorte que JSF appelle le setter de l'entité JPA. La validation JSF échoue avec ce message :

form:location : Erreur de validation : La valeur n'est pas valide

J'ai réussi à faire fonctionner plusieurs autres classes du même type (c'est-à-dire des classes de tables de jonction) mais je n'arrive pas à faire fonctionner celle-ci.

Si quelqu'un peut donner des conseils de dépannage/débogage pour ce genre de problème, ce sera très apprécié.

En utilisant les relevés de journal, j'ai vérifié ce qui suit :

  1. Le site Conveter renvoie des données correctes, non null valeurs.
  2. Je n'ai pas de Bean Validation dans mes entités JPA.
  3. Le setter setLocation(Location location) n'est jamais appelé.

C'est l'exemple le plus simple que je puisse faire et il 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 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]

145voto

BalusC Points 498232

La validation échoue avec le message "form:location : Erreur de validation : La valeur n'est pas valide".

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

Afin de se prémunir contre les demandes falsifiées ou piratées, JSF vérifiera à nouveau toutes les valeurs disponibles des éléments sélectionnés et testera 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 se déroule de la façon suivante bean.getAvailableItems() représente fictivement la liste complète des éléments sélectionnés disponibles tels que 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");
}

Ainsi, sur la base de la logique ci-dessus, ce problème peut logiquement avoir au moins les causes suivantes :

  1. L'élément sélectionné ne figure pas dans la liste des éléments disponibles.
  2. Le site equals() de la classe représentant l'élément sélectionné est manquante ou cassée.
  3. Si un Converter est impliqué, alors il a retourné le mauvais objet dans le fichier getAsObject() . Peut-être que c'est même null .

Pour le résoudre :

  1. Veillez à ce que la même liste soit conservée lors de la demande suivante, notamment en cas de menus multiples en cascade. Réalisation du haricot @ViewScoped au lieu de @RequestScoped devrait régler le problème dans la plupart des cas. Assurez-vous également que vous n'exécutez pas la logique métier dans la méthode getter de l'objet de l'utilisateur. <f:selectItem(s)> mais plutôt dans @PostConstruct ou une méthode d'événement d'action (écouteur). Si vous vous fiez à des paramètres de requête spécifiques, vous devez les stocker explicitement dans le fichier de configuration de l'action. @ViewScoped ou de les repasser lors de requêtes ultérieures, par exemple en utilisant la méthode suivante <f:param> . Voir aussi Comment choisir la bonne lunette de visée ?
  2. Assurez-vous que le equals() est implémentée correctement. Cela est déjà fait correctement sur les types Java standard tels que java.lang.String , java.lang.Number etc., mais pas nécessairement sur les objets, haricots et entités personnalisés. Voir aussi La bonne façon de mettre en œuvre un contrat égalitaire . Au cas où vous utiliseriez déjà String Vérifiez que le codage des caractères de la demande est bien configuré. S'il contient des caractères spéciaux et que JSF est configuré pour rendre la sortie en UTF-8 mais interprète l'entrée en ISO-8859-1, par exemple, il échouera. Voir aussi a.o. Les données Unicode récupérées via les composants d'entrée PrimeFaces sont corrompues. .
  3. Déboguer/enregistrer les actions de vos Converter et le corriger en conséquence. Pour les directives, voir également Conversion Error setting value for 'null Converter' (erreur de conversion) Au cas où vous utiliseriez java.util.Date comme articles disponibles avec <f:convertDateTime> Dans le modèle, veillez à ne pas oublier la partie temps plein. Voir aussi "Erreur de validation : Value is not valid" error from f:datetimeConverter .

Voir aussi :


Si quelqu'un peut donner des conseils de dépannage/débogage pour ce genre de problème, ce sera très apprécié.

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

0 votes

@BalusC : Où se trouve exactement dans le code mojarra, que cette equals le chèque arrive. Ma situation est un peu complexe. J'ai créé mon propre composant personnalisé qui permet à l'utilisateur d'avoir une disposition radio complexe. Cela fonctionne bien si je n'ai qu'un seul groupe de radios (f:selectItems juste en dessous de mon composant personnalisé). Cependant, lorsque la disposition devient plus complexe (plusieurs groupes de radios, chacun ayant ses propres f:selectItems mais partageant tous la même sélection), je dois placer les f:selectItems dans l'ui:repeat, et l'ui:repeat se trouve alors sous mon composant personnalisé. J'ai ensuite rencontré le problème suivant. Je veux voir le code mojarra qui gère ce problème.

0 votes

De plus, mes f:selectItems sont de type String, donc je suis sûr qu'il ne s'agit pas d'un problème de conversion. Je pense que la cause est que la liste des f:selectItems n'est pas présente pendant la phase de validation.

0 votes

Pouvez-vous préciser comment utiliser f:param pour envoyer un état au bean géré afin qu'il puisse recréer l'"état initial" ? Merci.

2voto

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 votre élément sélectionné, et se produit ce que BalusC a dit au point 1 de sa réponse :

1 . L'élément sélectionné est absent de la liste des éléments disponibles. Cela peut se produire si la liste des éléments disponibles est servie par un haricot à portée de requête qui n'est pas correctement réinitialisé lors d'une requête ultérieure, ou qui effectue incorrectement le travail professionnel à l'intérieur d'une méthode getter, ce qui l'amène à renvoyer une liste différente d'une manière ou d'une autre.

1voto

Cela peut être un problème de convertisseur ou 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'objet Location qui indique 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".

0 votes

Comme indiqué au point 2 de la réponse acceptée et largement approuvée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X