Error de validación: el valor no es válido

80

Tengo un problema con ap: selectOneMenu, no importa lo que haga, no puedo hacer que JSF llame al establecedor en la entidad JPA. La validación JSF falla con este mensaje:

formulario: ubicación: Error de validación: el valor no es válido

Tengo esto funcionando en varias otras clases del mismo tipo (es decir, unirse a clases de tabla) pero no puedo por mi vida hacer que funcione.

Si alguien puede ofrecer algunos consejos de solución de problemas / depuración para este tipo de problema, sería muy apreciado.

Usando declaraciones de registro, he verificado lo siguiente:

  1. El Conveterdevuelve nullvalores correctos, sin valores.
  2. No tengo validación de Bean en mis entidades JPA.
  3. El colocador setLocation(Location location)nunca es llamado.

Este es el ejemplo más simple que puedo hacer y simplemente no funcionará:

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

Convertidor:

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

Salida de consola:

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

Respuestas:

143

La validación falla con el mensaje "formulario: ubicación: Error de validación: el valor no es válido"

Este error se reduce a que el elemento seleccionado no coincide con ninguno de los valores de elemento de selección disponibles especificados por cualquier <f:selectItem(s)> etiqueta anidada durante el procesamiento de la solicitud de envío del formulario.

Como parte de la protección contra solicitudes manipuladas / pirateadas, JSF reiterará todos los valores de elementos seleccionados disponibles y probará si se selectedItem.equals(availableItem) devuelve trueal menos un valor de elemento disponible. Si ningún valor de elemento coincide, obtendrá exactamente este error de validación.

Este proceso se encuentra bajo las cubiertas básicamente como se muestra a continuación, por lo que bean.getAvailableItems()representa de manera ficticia la lista completa de elementos seleccionados disponibles según lo definido por <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");
}

Entonces, según la lógica anterior, este problema lógicamente puede tener al menos las siguientes causas:

  1. El elemento seleccionado falta en la lista de elementos disponibles.
  2. El equals()método de la clase que representa el elemento seleccionado no se encuentra o roto.
  3. Si Converterestá involucrada una costumbre , entonces ha devuelto el objeto incorrecto en formato getAsObject(). Quizás sea incluso null.

Para solucionarlo:

  1. Asegúrese de que se conserve exactamente la misma lista durante la solicitud posterior, especialmente en el caso de varios menús en cascada. Hacer el frijol en @ViewScopedlugar de @RequestScopeddebería solucionarlo en la mayoría de los casos. También asegúrese de no realizar la lógica empresarial en el método getter de <f:selectItem(s)>, sino en @PostConstructun método de evento de acción (oyente) o. Si confía en parámetros de solicitud específicos, entonces deberá almacenarlos explícitamente en el @ViewScopedbean o volver a pasarlos en solicitudes posteriores, por ejemplo <f:param>. Consulte también ¿Cómo elegir el alcance de frijol correcto?
  2. Asegúrese de que el equals()método se implemente correctamente. Esto ya se hace justo en los tipos Java estándar, tales como java.lang.String, java.lang.Number, etc, pero no necesariamente en objetos personalizados / frijoles / ENTIDADES. Consulte también Forma correcta de implementar un contrato igual . En caso de que ya lo esté utilizando String, asegúrese de que la codificación de caracteres de la solicitud esté configurada correctamente. Si contiene caracteres especiales y JSF está configurado para representar la salida como UTF-8 pero interpretar la entrada como, por ejemplo, ISO-8859-1, fallará. Consulte también ao La entrada Unicode recuperada a través de PrimeFaces se corrompe .
  3. Depura / registra las acciones de tu personalización Convertery arréglalo en consecuencia. Para conocer las pautas, consulte también Valor de configuración de Error de conversión para 'Convertidor nulo'. En caso de que esté utilizando java.util.Dateelementos disponibles con <f:convertDateTime>, asegúrese de no olvidar la parte de tiempo completo en el patrón. Consulte también el error "Error de validación: el valor no es válido" de f: datetimeConverter .

Ver también:


Si alguien puede ofrecer algunos consejos de solución de problemas / depuración para este tipo de problema, sería muy apreciado.

Haz una pregunta clara y concreta aquí. No hagas preguntas demasiado amplias;)

BalusC
fuente
@BalusC: ¿Dónde está exactamente en el código de mojarra que se realiza esta equalsverificación? Mi situación es un poco compleja. Creo mi propio componente personalizado que permite al usuario tener un diseño de radio complejo. Funciona bien si solo tengo un grupo de radio (f: selectItems justo debajo de mi componente personalizado). Sin embargo, a medida que el diseño se vuelve más complejo (varios grupos de radio, cada uno tiene su propio f: selectItems pero todos comparten la misma selección), tengo que tener f: selectItems dentro de ui: repeat, luego ui: repeat está debajo de mi componente personalizado. Luego me encontré con este problema. Quiero ver el código mojarra que maneja esto
Thang Pham
Además, mi f: selectItems es de tipo String, así que estoy seguro de que esto no es un problema de conversión, creo que esto se debe a que la lista de f: selectItems no está allí durante la fase de validación.
Thang Pham
¿Puede explicar cómo se usa f: param para enviar el estado al bean administrado para que pueda recrear el "estado inicial"? Gracias.
Agustí Sánchez
1
Tener un error similar. Estoy usando SelectItemsConverter y este componente está dentro de un conjunto de campos deshabilitado, por lo que también está deshabilitado. ¿Es un comportamiento conocido?
Gilberto
Si está usando enum para que los elementos se muestren y su bean de respaldo tiene el tipo String para establecer el valor en el bean y no usa ningún convertidor, obtendrá el mismo error. Así es como terminé aquí.
Philip Puthenvila
2

En mi caso, olvidé implementar un método get / set correcto. Sucedió porque cambié muchos atributos a lo largo del desarrollo.

Sin un método de obtención adecuado, JSF no puede recuperar el elemento seleccionado y sucede lo que dijo BalusC en el elemento 1 de su respuesta:

1. El elemento seleccionado falta en la lista de elementos disponibles. Esto puede suceder si la lista de elementos disponibles es servida por un bean con alcance de solicitud que no se reinicializa correctamente en una solicitud posterior, o si está realizando incorrectamente el trabajo comercial dentro de un método getter que hace que devuelva una lista diferente de alguna manera.

Henrique Liberato
fuente
1

Esto puede ser un problema de convertidor o un problema de DTO. Intente resolver esto agregando los métodos hashCode () y equals () en su objeto DTO; En el escenario anterior, puede generar estos métodos dentro de la clase de objeto Location que se indica como 'DTO' aquí.

Ejemplo:

@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;
}
  • Tenga en cuenta que el ejemplo anterior es para un 'id' de tipo 'long'.
Rizla Shareefdeen
fuente
Como se indica en el n. ° 2 en la respuesta aceptada y altamente votada
Kukeltje