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:
Conveter
renvoie des valeurs correctes et non null
.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]
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:
equals()
de la classe représentant l'élément sélectionné est manquante ou endommagée.Converter
personnalisé est impliqué, il a renvoyé le mauvais objet dans getAsObject()
. C'est peut-être même null
.Pour le résoudre:
@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?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 .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 .selectOneMenu
page wikiSi 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;)
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.
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;
}