Validar con métodos de retrollamada JPA
Vamos a probar otra forma más sencilla de hacer esta validación, simplemente moviendo la lógica de validación desde la clase validador a la misma entidad
Order, en este caso a un método
@PrePersist y
@PreUpdate.
Lo primero es eliminar la clase
DeliveredToBeInInvoiceValidator de tu proyecto. También quita la anotación
@EntityValidator de tu entidad
Order:
//@EntityValidator( // Eliminar '@EntityValidator'
// value=com.yourcompany.invoicing.validators.DeliveredToBeInInvoiceValidator.class,
// properties= {
// @PropertyValue(name="year"),
// @PropertyValue(name="number"),
// @PropertyValue(name="invoice"),
// @PropertyValue(name="delivered")
// }
//)
public class Order extends CommercialDocument {
Acabamos de eliminar la validación. Ahora, vamos a añadirla de nuevo, pero ahora dentro de la misma clase
Order. Escribe el método
validate() que se muestra a continuación dentro de tu clase
Order:
@PrePersist @PreUpdate // Antes de crear o modificar
private void validate() throws Exception {
if (invoice != null && !isDelivered()) { // La lógica de validación
// La excepción de validación del entorno Bean Validation
throw new jakarta.validation.ValidationException(
XavaResources.getString(
"order_must_be_delivered",
getYear(),
getNumber()
)
);
}
}
Antes de grabar un pedido esta validación se ejecutará, si falla una
ValidationException será lanzada. Esta excepción es del marco de validación Bean Validation, de esta forma OpenXava sabe que es una excepción de validación. Así con solo un método dentro de tu entidad tienes la validación hecha.
Sólo está permitido un método @PrePersist y un método @PreUpdate por entidad, por eso antes de ejecutar el código de arriba has de comentar las anotaciones @PrePersist y @PreUpdate que tenías en recalculateDeliveryDays(), de esta manera:
// @PrePersist @PreUpdate // Comenta estas anotaciones
private void recalculateDeliveryDays() {
setDeliveryDays(getEstimatedDeliveryDays());
}
No te preocupes, descomentaremos estas anotaciones más adelante. Aunque JPA sólo permita un método @PrePersist/@PreUpdate siempre tenemos la opción de crear un único método de retrollamada desde el cual llamar a todos los demás métodos que necesitemos, pero esto no hace falta en nuestro caso, porque no vamos a quedarnos con este estilo de validación como definitivo.
Ahora, intentar añadir pedidos no entregados a una factura y verás los errores de validación, como en nuestro primer ejemplo.
Validar en el setter
Otra alternativa para hacer tu validación es poner tu lógica de validación dentro del método setter. Es un enfoque simple y llano.
Después añade el método setter
setInvoice() a
Order:
public void setInvoice(Invoice invoice) {
if (invoice != null && !isDelivered()) { // La lógica de validación
// La excepción de validación del entorno Bean Validation
throw new jakarta.validation.ValidationException(
XavaResources.getString(
"order_must_be_delivered",
getYear(),
getNumber()
)
);
}
this.invoice = invoice; // La asignación típica del setter
}
Esto funciona exactamente como las dos opciones anteriores. Es parecida a la alternativa del
@PrePersist/@PreUpdate, solo que no depende de JPA, es una implementación básica de Java.
Validar con Bean Validation
Como opción final vamos a hacer la más breve. Consiste en poner tu lógica de validación dentro de un método booleano anotado con la anotación de Bean Validation
@AssertTrue.
Para implementar esta alternativa primero quita el método
setInvoice():
En las formas anteriores de validación nuestro mensaje de error era construído mediante dos argumentos,
year y
number, que en nuestro archivo
i18n son representados por
{0}/{1} respectivamente. Para el caso de validación con
@AssertTrue no podemos pasar estos dos argumentos para construir nuestro mensaje de error, sino que podemos declarar propiedades y propiedades calificadas del bean validado en la definición del mensaje, para eso cambia en
invoicing-messages_es.properties la entrada:
order_must_be_delivered=Pedido {0}/{1} debe estar entregado para ser añadido a una Factura
Fíjate que hemos cambiado
{0}/{1} por
{year}/{number}. OpenXava llenará
{year}/{number} con los valores de
year y
number que tenga el
Order que está siendo actualizado y no cumple la condición de validación.
Esta es la forma más simple de validar, porque solo anotamos el método con la validación, y es el entorno Bean Validation el responsable de llamar este método al grabar y lanzar la excepción correspondiente si la validación no pasa.
Resumen
En esta lección has aprendido varias formas de hacer validación en una aplicación OpenXava. En la siguiente lección vas a ver como validar al borrar y con eso habrás explorado todos los tipos de validaciones.