domingo, 3 de diciembre de 2017

Design by contract (Software engineering, Bertrand Meyer)

Software engineering (by Restless Aficionados)

1. Design by contract

As object-oriented techniques steadily gain ground in the world of software development. users and prospective users of these techniques are clamof object-oriented or more and more loudly for a “methodology” software construction - or at least for some methodological guidelines.

This article presents such guidelines, whose main goal is to help improve the reliability of software systems. Reliability is here defined as the combination of correctness and robustness or more prosaically, as the absence of bugs.

Everyone developing software systems. or just using them, knows how pressing this question of reliability is in the current state of software engineering. Yet the rapidly growing literature on object-oriented analysis, design, and programming includes remarkably few contributions on how to make object-oriented software more reliable. This is surprising and regrettable, since at least three reasons justify devoting particular attention to reliability in the context of object-oriented development:
The cornerstone of object-oriented technology is reuse. For reusable components, which may be used in thousands of different applications, the potential consequences of incorrect behavior are even more serious than for application specific developments.
Proponents of object-oriented methods make strong claims about their beneficial effect on software quality. Reliabitity is certainly a central component of any reasonable definition of quality as applied to software.
*The object-oriented approach, based on the theory of abstract data types, provides a particularly appropriate framework for discussing and enforcing reliability.
Reliability is even more important in object-oriented programming than elsewhere. This article shows how to reduce bugs by building software components on the basis of carefully designed contracts.

The pragmatic techniques presented in this article, while certainly not providing infallible ways to guarantee reliability, may help considerably toward this goal. They rely on the theory of design by contract. which underlies the design of the Eiffel analysis, design, and programming language’ and of the supporting libraries, from which a number of examples will be drawn.

The contributions of the work reported below include a coherent set of methodological principles helping to produce correct and robust software; a systematic approach to the delicate problem of how to deal with abnormal cases. leading to a simple and powerful exception-handling mechanism; and *a better understanding of inheritance and of the associated techniques (redeclaration, polymorphism, and dynamic binding) through the notion of subcontract, allowing a systematic approach to using these powerful but sometimes dangerous mechanisms.

Most of the concepts presented here have appeared elsewhere. They were previewed in the book “Object-Oriented Software Construction”; and a more complete exposition was presented in a recent book chapter,”from which this article has been adapted”. More profoundly, this work finds its root in earlier work on systematic program development and abstract data types. This article focuses on the central ideas, introducing them concisely for direct application by developers.

1.1. Defensive programming

1.2. The notion of contract

1.3. Assertions:Contracting for software

1.4. The role of assertions

1.5. Further sources

1.6. Observations on software contracts

1.7. Who should check?

1.8. Class invariants

1.9. On the assertion language

1.10. Documenting a software contract

1.11. Monitoring assertions

1.12. Why monitor?

1.13. Introducing inheritance

1.14. The concurrency issue

1.15. Invariants and dynamic binding

1.16. Dealing with abnormal situations

1.17.A disciplined exception-handling mechanism

1.18. Status of Eiffel

1.19. Acknowledgments

2. References

B. Meyer. “Design by Contract.” in Advances in Object-Oriented Software Engineering, D. Mandrioli and B. Meyer.eds.. Prentice Hall. Englewnod Cliffs, N.J.. 1991. pp. I-SO.

lunes, 5 de junio de 2017

Requisitos y patrones J2EE aplicables

Requisites and applied J2EE Patterns

1. Requisitos y Patrones de diseño en J2EE

Presentaremos una lista de requisitos que surgen a la hora de crear una aplicación J2EE. Junto al requisito, se indica el o los patrones que se suelen aplicar. Esto puede ser util a la hora de identificar cual puede ser (los) patrones a aplicar.

1.1. Capa de presentacion

Requisitos

Patrones

Preprocesamiento o postprocesamiento de la request

Intercepting Filter

Añadir la capacidad de logging, depuracion, u otro comportamiento que debe completar cada request

Front Controller

Intercepting Filter

Centralizar el control para el manejo de la request

Front Controller

Intercepting Filter

Application Controller

Crear un interfaz generico de tipo Command o un objeto que contenga el contexto, de manera que se reduzca el acoplamiento entre los elementos que manejan el control c y los elementos que actuan como helpers

Front Controller

Application Controller

Context Object

Si hemos de implementar nuestro Controller como un servlet o bien como JSP

Front Controller

Crear una vista a partir de varias sub-vistas

Composite View

Si hemos de implementar nuestra View como un servlet bien como JSP

View Helper

Como descomponer nuestra View y Model

View Helper

Donde encapsular los datos provenientes de la presentacion y su logica

View Helper

Si debemos de implementar nuestros Helpers como JavaBeans o como Custom tags

View Helper

Combinar multiples patrones de presentación

Intercepting Filter

Dispatcher View

Donde encapsular el manejo de la Vista y la lógica de Navegacion, lo que implica seleccionar una de las Vistas y servirla

Pattern Service to Worker

Dispatcher View

Donde guardar el estado de la Session

Session State on the Client

Session State in the Presentation Tier

Storing State on the Business Tier

Control de acceso del cliente a ciertas vistas

Design "Controlling Client Access"

Hide Resources From a Client

Controlar el flujo de requests hacia la aplicacion

Design "Duplicate Form Submissions"

Design "Introduce Synchronizer Token"

Controlar la llegada de submits duplicados

Design "Duplicate Form Submissions"

Introduce Synchronizer Token

Problemas de diseño al usar el mecanismo de populacion de valores estandar de JSP <jsp:setProperty>

"Helper Properties—Integrity and Consistency"

Reducción del acoplamiento entre la capa de presentación y la de negocio

"Hide Presentation Tier-Specific Details From the Business Tier"

"Introduce Business Delegate"

Particionar el codigo de acceso a datos

"Separate Data Access Code

1.2. Capa de negocio

Requisitos

Patrones

Reducir el acoplamiento entre la capa de presentación y la capa de negocio

Business Delegate

Poner en cache los servicios de la capa de negocio a los clientes

Business Delegate

Ocultar los detalles de implementacion de lookup/creacion/acceso de los servicios de la capa de negocio

Business Delegate

Service Locator

Encapsular las dependencias propietarias de lookup en los servicios

Service Locator

Proveer un metodo uniforme para lookup y creacion en los servicios de la capa de negocio

Service Locator

Ocultar la complejidad de las dependencias de los enterprise bean y el lookup de los componentes JMS

Service Locator

Transferir los datos entre los objetos de negocio y los clientes pasando por las distintas capas

Transfer Object

Proveer de un interfaz simple para los clientes remotos

Business Delegate

Session Façade

Application Service

Reducir las invocaciones a metodos remotos mediante el acceso a metodos que agrupen varias funcionalidades dentro de la capa de negocio

Session Façade

Manejar las relaciones entre los componentes enterprise bean y ocultar la complejidad de las interacciones

Session Façade

Proteger los componentes de la capa de negocio de ser expuestos directamente al cliente

Session Façade

Application Service

Proveer una capa uniforme de acceso a los componentes de la capa de negocio

Session Façade

Application Service

Implementar un modelo conceptual de dominio complejo mediante objetos

Business Object

Identificar objetos que manejan dependencias y sus objetos dependientes en el diseño de objetos de negocio y entity beans

Business Object

Composite Entity

Diseñar entity beans que manejan varias otras dependencias

Composite Entity

Reducir o eliminar la dependencia entre entity beans y el esquema de base de datos

Composite Entity

Reducir o eliminar la dependencia entre entity beans locales y entity beans remote

Composite Entity

Reducir el numero de entity beans y mejorar su manejo

Composite Entity

Obtener el modelo de datos de la aplicacion a partir de componer varios componentes de la capa de negocio

Transfer Object Assembler

Construcción dinamica del modelo de datos de aplicacion

Transfer Object Assembler

Ocultar la complejidad de la construcción del modelo de datos a los clientes

Transfer Object Assembler

Proveer de un procesamiento de peticiones y resultados en la capa de negocio

Value List Handler

Reducir la sobrecarga del uso de metodos lookup de enterprise bean

Value List Handler

Proveer de peticion-resultados cacheados para el cliente, dentro del servidor, con posibilidad de hacer-deshacer

Value List Handler

Elegir entre el uso de sessions beans con estado o sin el

Session Bean—Stateless Versus Stateful

Evitar el acceso directo por parte del cliente a entity beans

Wrap Entities With Session

Encapsular los servicios de la capa de negocio y ocultar los detalles de implementación

Introduce Business Delegate

Añadir logica de negocio dentro de un entity bean

Business Logic in Entity Beans

Move Business Logic to Session

Crear session beans como gruesos servicios de la capa de negocio

Merge Session Beans

Wrap Entities With Session

Reducir o eliminar sobrecargas de red o servidor debido a la comunicacion entity-bean-to-entity-bean

Reduce Inter-Entity Bean Communication

Particionar el codigo de acceso a datos

Separate Data Access Code

1.3. Capa de integracion

Requisitos

Patrones

Reducir el acoplamiento entre la capa de negocio y la de recursos

Data Access Object

Centralizar el acceso a la capa de recursos

Data Access Object

Minimizar la complejidad de los componentes de la capa de recursos y los de la capa de negocio

Data Access Object

Proveer procesamiento asincrono en aplicaciones empresariales

Service Activator

Enviar una peticion asincrona hacia los servicios de la capa de negocio

Service Activator

Procesamiento asincrono de una peticion, subdividiendola en sub tareas concurrentes

Service Activator

Persistir de manera transparente un objeto del modelo

Domain Store

Implementar un framework de persistencia propio

Domain Store

Exponer un servicio web mediante XML y un protocolo standard de Internet

Web Service Broker

Ofrecer de forma centralizada y distribuir servicios existentes bajo la forma de web services

Web Service Broker

2. Enlaces de interes

jueves, 13 de abril de 2017

POC of Suscription Board (Dojo,Dojo mobile, Spring MVC, JPA, Hibernate, Mysql)

You can find a Proof of concept of a "suscription board project", using: Dojo, Dojo mobile, Spring, JPA, Hibernate, Mysql and Amazon AWS technologies, at:

http://discussion.puertocerouno.net

Project now supports:

  • File attachments for discussion and replies

Regards.

jueves, 22 de septiembre de 2016

Entendiendo RESTful Web services

Entendiendo RESTful web services

1. RESTful Web services

1.1. Introduccion

Representational State Transfer (REST), es un concepto de web service que se parece en muchos aspectos a SOAP. La arquitectura REST esta formada por varios servidores y clientes. Los clientes realizan transiciones entre estados mediante acciones (peticiones a servidor para obtener o realizar un cambio de estado en los recursos), el servidor por su lado procesa las peticiones y devuelve los recursos. Un recurso puede ser cualquier concepto logico que es comprendido por ambos, cliente y y servidor, y que se transmite de forma acordada bajo una representacion. REST no depende o indica explicitamente un tipo de recurso o representacion. Dichos recursos pueden ser de cualquier tipo de dato que podamos establecer. Sus representaciones pueden ser por ejemplo, texto plano, HTML, XML, YAML, JSON, datos binarios, o cualquier otro tipo de formato que se entienda por el cliente y el servidor. Un sistema REST trabaja mediante URLs las cuales indican el tipo de recurso del que se trata, e instrucciones (veremos con el mapeo al protocolo HTTP, tales como GET, POST...), que indican la accion que se ha de realizar sobre el recurso, ademas del tipo de medio que representa el recurso (indicado por el MIME type), a tratar en las request y response. Es normal que nos recuerde a la forma de comunicacion de la WWW y el protocolo HTTP. Ademas de creador de parte del protocolo HTTP 1.0 y 1.1 Roy Fielding habla de “Representational State Transfer” en su tesis doctoral de 2000. World Wide Web es, por naturaleza, el gran sistema REST.

Uno de los principios fundamentales de los servicios RESTful es que se basa en un numero reducido de operaciones, que han de ser realizadas sobre un recurso. En este caso, el conjunto de operaciones se conoce como CreateReadUpdateDelete. Estos metodos se asignan a operaciones del protocolo HTTP facilmente sobre las acciones POST, GET, PUT y DELETE , respectivamente, mientras que SOAP utiliza el elemento envelope para indicar que tipo de accion realizar (el metodo que ha de ser invocado), REST basa las operaciones dentro del protocolo HTTP. En SOAP, el envelope, contiene ademas la referencia al recurso sobre el que se actua, mientras que REST dicha referencia va implicita en la URL.

En un servicio RESTful, la cabecera de peticion “Content-Type” indica al servidor acerca del la representacion del cuerpo de dicha peticion; la cabecera “Accept” o la extension de fichero en la URL, solicita el recurso de un tipo concreto, la cabecera de la respuesta “Content-Type”, informa al cliente la representacion del cuerpo de la respuesta.

Veamos algunas ventajas y desventajas que ofrece cada uno de los protocolos. La primera, un ws RESTful esta ligado a HTTP, miestras que SOAP es independiente del protocolo, lo que da ventaja a SOAP. Aunque no seria imposible crear un ws RESTful que fuese independiente, esto añadiria complejidad y dejaria de cumplir el concepto de REST. Ya que REST maneja: URLs, acciones y tipos de medio, al igual que lo hace HTTP lo que sirve como envelope para las request, response. Es posible con un mapeo directo a HTTP utilizar distintos tipos de dato, mientras que SOAP necesita que se pase a XML. SOAP es un protocolo redundante ya que se trata de un envelope contenido dentro de otro. Esta duplicidad del elemento envelope a la vez permite que sea independiente del protocolo HTTP y duplica la funcionalidad que ofrece directamente la referenciacion del recurso por URL y las acciones con metodos HTTP.

Una desventaja de los web services RESTful es que carecen de un tipado definido, como el que tiene SOAP a traves de los esquemas WSDL. Esto hace que no exista un contrato propio predefinido entre la peticion y la respuesta sino lo que se llama “contract-last”. Esto no impide que se pueda establecer dicho contrato, pero esta basado en una documentacion, haciendolo disponible mediante un API publica, en contraposicion a complejos esquemas XSD. Sin embargo algunos proveedores de ws RESTful llegan incluso a publicar dicha especificacion mediante un esquema XSD o en formato JSON.

plificar la funcionalidad aún siendo dependiente del protocolo HTTP, la aquitecutra RESTful se esta imponiendo a la hora de implementar Web Services y se integra ya en varios frameworks tales como Spring MVC.

1.2. Discoverability e Hypertext Application Language (HAL)

Una caracteristica importante de los ws RESTful es su “discoverability”. Mediante una combinacion de URL y metodos HTTP como OPTIONS, los clientes pueden descubrir los recursos disponibles que ofrece el web service, sin tener que establecer un contrato previo. De esta manera los clientes pueden saber las acciones que se pueden realizar sobre cada recurso. Aunque muchos proveedores de ws RESTful no ofrecen dicha posibilidad, es una ventaja central de la arquitectura REST. En WWW todo es posible de identificar mediante su URL, como usuario, es posible desde el navegador acceder a cualquier recurso publico y siguiendo la cadena de enlaces llegar al resto.

Esta restriccion se encuentra tambien dentro de las especificaciones REST. De manera que sea posible acceder a un recurso a partir de otro. Este concepto se conoce como “Hypermedia as the Engine of Application State” (HATEOAS), para ello se usa XML, YAML, JSON, o cualquier otro formato junto con hiperenlaces para informar al cliente acerca de la estructura del ws. Por ejemplo, una request-response hacia un web service podria ser de la siguiente manera.

/*peticion*/
GET /servicios/rest/ HTTP/1.1
Accept: application/json

200 OK

Content-Type: application/hal+json

{

"_directorio": {

"self": { "href": "http://site.net/servicios/rest" },

"cuenta": { "href": "http://site.net/servicios/rest/cuenta" },

"pedido": { "href": "http://site.net/servicios/rest/order" }

}

}

Asi el cliente conoce los recursos disponibles en el web service. Si desea acceder al servicio de “cuenta” mas adelante, puede realizarlo o bien mediante una peticion GET al un recurso especifico llamado una “collection request” o bien una peticion a una URI, que devuelve todos los recursos de ese tipo disponibles.

GET /services/Rest/account HTTP/1.1

Accept: application/json


200 OK

Content-Type: application/json

{

"value": [

{

"id": 1075,

"name": "Joe Doe",

...

}, {

"id": 1076,

"name": "Alice Green",

...

}

]

}

Esto presenta la desventaja de que la respuesta con la coleccion puede ser muy grande (enorme incluso). La solucion seria aplicar paginacion en la respuesta. Otro problema, es que se muestran los recursos propiamente, no su ubicacion (mediante una URL por ejemplo). Para esto una forma seria devolver una lista de enlaces, pero esto lo hace inviable a la hora de utilizar estos datos por la parte cliente. Por esta razon, muchos web services usan una combinacion de atributos y un enlace al recurso.

Otra accion que puede realizar el cliente es solicitar los recursos disponibles dentro del un recurso devuelto mediante la peticion OPTIONS a dicho recurso.

OPTIONS /servicios/rest/cuenta HTTP/1.1

Accept: application/json
/*respuesta*/

200 OK

Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE

{

"GET": {

"description": "Recursos disponibles dentro de cuentas",

"templateAcceso": "http://site.net/servicios/rest/cuenta/{id}",

"parametros": {

"$select": {

"type": "array/string",

"description": "Propiedades de cada recurso disponible.",

},

"$filter" ...

}

},

"POST" ...

}

La respuesta OPTIONS puede ser muy util ya que no solamente indica al cliente cuales son las acciones que puede realizar sobre el recurso, sino que puede ademas filtrarse de acuerdo con los “permisos” que dicho cliente tenga. Por ejemplo, si el cliente puede Read pero no Create, Update o Delete, la response devolveria la cabecera “Allow: OPTIONS,HEAD,GET “. Junto con las acciones que fuesen posibles para los distintos recursos y sus parametros como vemos en la siguiente peticion y sus respuestas:


OPTIONS /services/rest/cuenta/1075 HTTP/1.1

Accept: application/json

200 OK

Allow: OPTIONS,HEAD,GET,PUT,PATCH,DELETE

….

OPTIONS /services/rest/cuenta/1076 HTTP/1.1

Accept: application/json

200 OK

Allow: OPTIONS,HEAD,GET

 ...

El primer problema para descubrir los servicios web RESTful es que no existe un acuerdo previo establecido entre cliente y servidor acerca del formato de las reponses de tipo “discovery” (OPTIONS).

En los ejemplos hemos visto el uso de una representacion JSON de Hypertext Application Language (HAL), lo que es, uno de los standares emergentes pero no es el unico. En cuanto al contenido del cuerpo de la respuesta, no hay un protocolo, a menudo depende de la implementacion del API.

2. Enlaces de interes

Algunos enlaces:

viernes, 2 de septiembre de 2016

Introduccion a Groovy

Introduction to Groovy

1. En Java...en Groovy

Ejemplo basico en Java :

public class HelloEcho {
   public static void main( String[] args )
      System.out.println("Hello Echo!");
   }
}

Se ejecutaria tambien en Groovy !!

Veamos otras caracteristicas del lenguaje :

1) Es debilmente tipado, como JavaScript o Perl. 2) El ambito de metodos y atributos de clase es por defecto public. 3) Punto y coma al final de linea es opcional

asi, la sintaxis siguiente seria correcta:

class HelloEcho {
   static main( args ){
 def avar = « Echo ! »
 println "Hello ${ avar }"
   }
}

Ademas, como dijimos Groovy es un lenguaje dinamico, lo que no impide que sea un lenguaje interpretado. De heco, cada clase Groovy se compila como una clase Java (lo que lo distingue de otros lenguajes de la JVM), aun cuando escribimos y ejecutamos el codigo desde scripts (no clases formales), se compilara como clase Java.


//se compila en Java bytecode
println "Hello World!"
Otra forma, en Groovy, usando  clases :
class HelloEcho {
   def greet( snds ){
      "Hello ${snds}!"
   }
}

def earv = new HelloEcho()
println earv.greet("Echo !")

En el ejemplo vemos 3 caracteristicas del lenguaje:

1) El tipo de retorno del metodo "greet"" no es de un tipo concreto, asi que usamos el keyword def (semejante a var en JS). 2) Si no indicamos « return » el valor de retorno sera el devuelto por la ultima sentencia ejecutada. 3) La cadena « Echo ! » no es de tipo java.lang.String, esto es una de las caracteristicas mas interesantes, es de tipo « GString ». Este tipo de strings nos permiten evaluar variables en su interior asi como expresiones, similar a como hace el lenguaje Perl.

2. Instalando Groovy

Para la instalar Groovy y lanzar los ejemplos desde la consola :

1) Descargar la ultima version desde http://groovy.codehaus.org/Download

2) En Windows existe el instalador NSIS-Installer, para versiones en Ingles, Español, Aleman y Frances.

3) Instalacion manual : Descomprime el paquete en un directorio, con permisos suficientes, por ejemplo C:\groovy en Windows, /usr/local/groovy en Linux.

4) Crear la variable de entorno GROOVY_HOME que apunte hacia ese directorio.

5) Debes tener instalado Java (JRE 1.4 o superior), y declarada la variable JAVA_HOME.

6) Añadir al PATH : GROOVY_HOME/bin

Ya puedes ejecutar scripts *.groovy ! Puede hacerlo de 3 formas :

1) La mas sencilla es a partir de ejecutar el interprete (es un lenguaje script, recuerda!). Asi el ejemplo anterior se ejecutaria desde la linea de comandos :

// hello-echo.groovy tiene permisos de ejecucion
$>groovy hello-echo.groovy

2) Lanzar el propio shell de groovy : groovysh

3) Lanzar la consola basada en Java Swing de Groovy , esta es la opcion mas recomendada para principiantes (no olvides configurar en las opciones, los jar necesarios para el classpath).

3. Tipos de dato

Una vez instalado Groovy (ya veremos como añadirlo a IDEs como Eclipse, mediante sus Plug-in), empezaremos a explorar el lenguaje. Empezando por los tipo de dato que soporta. Al contrario de Java, en el que existen tipos basicos, en Groovy todo es objeto (Smalltalk). Ademas, a la hora de ejecutar una sentencia, por ejemplo un bucle, existen multiples formas de hacerlo. Por ejemplo :

//escribe hola 3 veces
3.times {
   println "hola"
}
(1..3).each {
   println "hola"
}

El codigo print »Hola » se encuentra dentro de lo que se define como Closure, es importante este concepto de bloques de codigo. En Groovy se aceptan todos los tipos de tato Java (para ello se llama a los wrappers -Integer, Double,Boolean…-, en lugar de los tipos basicos). Para las collections como maps y list, se tratan de forma parecida a PHP o Perl. Las listas son en realidad instancias de  java.util.ArrayList  y los maps de java.util.HashMap, por lo que disponemos de sus metodos, sin embargo Groovy añade la posibilidad de acceder a los indices con el operador '[]' y en el caso de maps con la notacion punto.


//List y Maps en Groovy
def lista = [9,1,2,8,3,0,4,5,7,8, 2,4, 0, 0, 1]
def map = ["clave":"valor"]

//
assert list.get(0) == 9
assert list[0] == 9
assert map.get("clave") == "valor"
assert map["clave"] == "valor"
assert map.clave == "valor"
assert map."clave" == "valor

def listVacia = []
def mapVacio = [:]

// En listas no necesario el operador .add() 
def lista = []
lista[9] = 10
assert lista[9] == 10
assert lista.size() == 10 
//iterar lista.each{ item →...}

El uso de rangos define una secuencia de valores que puede iterarse en ambos sentidos. Se usan a menudo para crear listas dentro de una lista, pero puede usarse en mas casos.


// operador rango [] en un string es semejente a substring() o charAt() on the string
println "Soyunstring"[0..7]
// salida : Soyunstr

//bucle indicado por un rango
(0..10).each { num -> print num }
// prints 012345678910
('a'..'d').each { letra -> print letra }
// prints abcd

En Groovy existen ademas otros metodos que se añaden a las colecciones. Estos vienen con el GDK. Para muchos de estos metodos, se usan las Closures del lenguaje.

4. Closures

Veamos algunos ejemplos de closures, podemos comprenderlo como bloques de codigo reutilizables.

//Scope
def nombre = "Abracadabra"
def conjuro = {
   println nombre
}
conjuro()
// escribe « Abracadabra »

Las closures son similares a « funciones anonimas » dentro de un script. Podemos pasar parametros, el tipo y el nombre, pero al tratarse de un lenguaje dinamico, el tipo se puede obviar:

def escribe = { elem -> print elem }
(0..9).each escribe
('a'..'f').each escribe
//0123456789abcdef

Existen parametros por defecto para las Closures, incluso si no lo declaramos, disponemos de, « it »

def escribe = { print it }
(0..9).each escribe
('a'..'f').each escribe
//  0123456789abcdef

// Otras formas de iterar
//1
[0,1,2,3,4,5,6,7,8,9].each escribe
//2
(0..9).each escribe
//3
10.times escribe
//4
0.upto 9, escribe
//5 
def lista =[0,1,2,3,4,5,6,7,8,9] 
for( num in lista) escribe.call(num)

En el caso del bucle « for », hay que usar una llamada a « call » dentro de « escribe ». Esto se debe a que for no puede acceder al cuerpo de la closure de « escribe », sino que debe ser un bloque semejante a Java. (ver la declaracion de « escribe »)

5. Enlaces de interes

Algunos enlaces:

martes, 9 de agosto de 2016

Bean Validation en Spring

Bean Validation en Spring

1. Introduccion a Bean Validation en Spring

Trabajaremos con las siguientes dependencias Maven:


javax.validation
validation-api
1.1.0.Final
compile


org.hibernate
hibernate-validator
5.1.0.Final
runtime




org.jboss.logging
jboss-logging
3.2.0.GA
runtime

1.1. Que es "Bean Validation"

En grandes aplicaciones, nos encontramos con el caso de tener que almacenar complejos objetos de negocio que se han de persistir de alguna manera.

La mayoria de estos objetos han de cumplir una serie de reglas de negocio. Por ejemplo, pensemos en un objeto “Usuario”, muy posible que los valores de sus atributos “username”, “password” deban ser “No nulos”, cumplir con una determinada longitud minima e incluso un contener un conjunto de caracteres especificos. Por otro lado, un objeto “CarritoDeCompra”, podria estar restringido a que su atributo “cantidad” sea mayor que 0 antes de ser guardar y “duracionCompra” estar dentro de un rango que permita la aplicacion.

A veces, dichas reglas de negocio pueden tornarse bastante complejas. La expresion regular que se usa para validar una dirección “e-mail”.

^[a-z0-9`!#$%^&*'{}?/+=|_~-]+(\.[a-z0-9`!#$%^&*'{}?/+=|_~-]+)*@ ([a-z0-9]([a-z0-9-]*[a-z0-9])?)+(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$

Esta parte de validacion de reglas de negocio, puede resultar bastante engorrosa teniendo en cuenta el numero de reglas por Objeto(s) y la cantidad de codigo que requieren. Veamos un ejemplo de objeto “Cliente”:


/*Ejemplo de validacion corriente del objeto "Customer" */

if(customer.getFirstName() == null ||
customer.getFirstName().trim().length() == 0)
throw new ValidationException("validate.customer.firstName");
if(customer.getLastName() == null || customer.getLastName().trim().length() == 0)
throw new ValidationException("validate.customer.lastName");
if(customer.getGovernmentId() == null ||
customer.getGovernmentId().trim().length() == 0)
throw new ValidationException("validate.customer.governmentId");
if(customer.getBirthDate() == null ||
customer.getBirthDate().isAfter(yearsAgo(18)))
throw new ValidationException("validate.customer.birthDate");
if(customer.getGender() == null)
threw new ValidationException("validate.customer.gender");
if(customer.getBadgeNumber() == null ||
customer.getBadgeNumber().trim().length() == 0)
throw new ValidationException("validate.customer.badgeNumber");
if(customer.getAddress() == null || customer.getAddress().trim().length() == 0)
throw new ValidationException("validate.customer.address");
if(customer.getCity() == null || customer.getCity().trim().length() == 0)
throw new ValidationException("validate.customer.city");
if(customer.getState() == null || customer.getState().trim().length() == 0)
throw new ValidationException("validate.customer.state");
if(customer.getPhoneNumber() == null ||
customer.getPhoneNumber().trim().length() == 0)
throw new ValidationException("validate.customer.phoneNumber");
if(customer.getEmail() == null || customer.getEmail().trim().length() == 0 ||
!EMAIL_REGEX.matcher(customer.getEmail()).matches())
throw new ValidationException("validate.customer.email");
if(customer.getDepartment() == null ||
lookupService.getDepartment(customer.getDepartment()) == null)
throw new ValidationException("validate.customer.department");
if(customer.getLocation() == null ||
lookupService.getLocation(customer.getLocation()) == null)
throw new ValidationException("validate.customer.location");

Como vemos, no hemos escrito aún el codigo para persistir a “customer” y vemos la cantidad de necesario para verificar unicamente si “customer” es correcto.

Afortunadamente, el API de Bean Validation nos permitira validar de manera declarativa (como veremos) los distintos beans. Esto se realiza a traves de unas anotaciones con las que se escriben las reglas de negocio para una clase dada, junto con el API para manejar los objetos de Validacion.

Basada en la JSR 303, JavaBean Validation 1.0, se añadio a la plataforma Java EE 6. Por otro lado Javabean validation 1.1, se basa en la JSR 349, es su sucesora en Java EE 7. Esta ultima añade como mejora, la validacion de los argumentos y validacion de los valores de retorno de un metodo, permite ademas el uso de “expresiones” dentro de los mensajes de error de validacion. En los ejemplos usaremos la implementacion Hibernate Validator 5.1.

1.2. Hibernate Validator

Mientras que JSR 349 especifica que debe cumplir el API de validacion y los metadatos. Hibernate Validator 5.0 es la implementacion de dicha JSR 349, ademas es la mas comunmente usada. (Existe una version 5.1 con numerosas mejoras).

Hibernate Validator es el punto de partida del standard Bean Validation. Inicialmente, Hibernate Validator formaba parte del framework ORM Hibernate, aportando la validacion de entidades antes de persistirlas en la base de datos. Mas tarde, evolucionaria hacia el estandard Bean Validation.

1.3. Comprendiendo Annotation Metadata Model

El funcionamiento de Bean Validation se realiza mediante la anotacion de atributos, metodos y demas, de manera que establecemos una restriccion sobre el elemento anotado. Para cualquier anotacion cuya “retention policy” es runtime (la anotacion sigue existiendo despues de compilar y esta disponible como metadato en runtime) y que se anota mediante @javax.validation.Constraint representa dichas restriccion. El API provee con anotaciones predefinidas, pero es posible crear nuestras propias “javax.validation.ConstraintValidator”. Un ConstraintValidator se encarga de procesar un tipo de constraint concreto. is responsible for evaluating a particular constraint type. Las constraints que aporta el API por defecto, no se crean a partir de ConstraintValidator s ya que se manejan de manera interna por el API.

Las anotaciones de Constraint al aplicarlas a un atributo, indican al validador que debe comprobar que se cumple, cada vez que se invoca el metodo de validacion en una instancia de dicha clase. Cuando se coloca en un setter/getter de un JavaBean, se trata de una alternativa a anotar directamente el atributo. Anotar un metodo de un interfaz indica que la constraint debe aplicarse sobre el valor de retorno de dicho metodo. Anotar uno o varios parametros de un metodo de un interfaz indica que dichos parametros han de validarse antes de la ejecucion del metodo. Estas dos ultimas formas de aplicar constraints facilitan el estilo de “programacion por contrato” (PbC). El creador del interfaz, especifica un contrato que debe cumplir dicha interfaz, como unos valores que deben ser siempre “No Nulos”, o que los parametros de sus metodos deben cumplir ciertas reglas. El consumidor del interfaz, de manera que la parte de la implementacion y la parte consumidora sabran que el contrato se rompe si se viola alguna de las constraints.

Con las anotaciones Bean Validation usadas como constraints de PbC , necesitamos crear un proxy para validar las clases de contendran la implementacion. Esto nos sugiere de una forma la Inyeccion de Dependencias (DI), de los Consumidores para realizar la llamada efectiva al proxy con su implementacion. Existen varios Java EE AS que implementan la capacidad que ofrece Java EE 7 de realizar Programacion por Contrato, mediante proxies que aplican DI validada. Sin embargo, cuando usamos un contenedor de servlets como puede ser Tomcat, debemos aportar nuestra propia solucion para DI.

1.4. Aplicar Bean Validation en Spring

El Framework Spring, crea automaticamente los proxies necesarios para los beans que maneja y que usan Java Bean Validation. Las llamadas a los metodos anotados, se interceptan y validan apropiadamente, ya sea o bien los argumentos que pasa el Consumer son validos, o bien que el valor retornado por la implementacion es correcto. De esta manera, es frecuente el uso de Bean Validation en clases de tipo @Service ya que de forma conceptual, se trata de los beans que han de manejar la logica de negocio. El framework tambien valida cualquier tipo de objeto o metodo anotado con constraints que se pasan a un metodo de @Controller si dichos parametros se marcan con @javax.validation.Valid .

2. Configurar Bean Validation en Spring

Aun cuando no configuremos Bean Validation dentro de Spring, podemos hacer uso de la validacion, si lo tenemos dentro de nuestras dependencias.

Una prueba seria:


ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
Validator validator = factory.getValidator(); 

Set  violations = validator.validate(employee); 
if(violations.size() > 0) 
throw new ConstraintViolationException(violations); 

Aunque el codigo funcionaria, no es nuestra intencion usarlo asi. Queremos usarlo de manera mas automatizada, para conseguirlo debemos configurar 4 puntos:

1. Declarar un “validator” 2. Configurar Message localization para el “validator” 3. Declarar “method validation processor” 4. Incluir el validator en Spring MVC form validation

En cuanto a la Maven dependency de Hibernate Validator excluye la dependencia JBoss Logging API (ya que Hibernate la usa en lugar de la dependencia Commons Logging como su API para loggings), y esto se hace en runtime, por lo que JBoss Logging dependency se declara de forma independiente. El artifact hibernate-validator declara una dependencia sobre una version de jboss-logging que no soporta Log4j 2, asi que es necesario incluir la dependencia mas reciente que lo soporte. La exclusion no es absolutamente necesaria, pero se muestra como aclaracion.

Antes de la version de Spring 4.0, el soporte para Bean Validation se centraba en las implementaciones Hibernate Validator 4.2 o 4.3. Esto es debido a que dicha implementacion aporta ciertas caracteristicas necesarias para aspectos de Spring i18n. Sin embargo en Spring 4.0, cualquier implementacion de Bean Validations 1.1 funciona ya que en esta version dichas caracteristicas se han estandarizado. En caso de estar restringidos al uso de Bean Validation 1.0 nos vemos forzados a usar Hibernate Validator (4.2 o 4.3).

2.1. Configurar Spring Validator Bean

El soporte automatico para validar objetos en Spring es anterior a que los estandares de Bean Validation apareciesen. La interfaz org.springframework.validation.Validator indica una forma de validar objetos basada en annotation constraints. Dichas constraints y su aplicacion se uso al principio dentro del proyecto llamado Spring Modules Validation, que desaparecio al aparecer el estandar JSR 303. Actualmente esta interfaz de Spring Validator sirve como facade para el API Bean Validation. Es importante tener esto en cuenta ya que los errores de validacion que reporta Spring los realiza a traves del interfaz org.springframework.validation.Errors y no en una coleccion retornada de tipo Set<javax .validation.ConstraintViolation<?>> . . La interfaz Errors, permite acceder a uno o varios objetos org.springframework.validation.ObjectError y a uno o varios org.springframework .validation.FieldError. A fecha actual, es posible usar Spring Validator o bien javax.validation.Validator, segun prefiramos, pero existen casos en los que nos vemos forzados a utilizar Spring Validator y sus objetos Errors .

Nota Para evitar confundirnos, cada vez que nos referimos a “ Validator ”, nos estamos refiriendo a javax.validation.Validator a menos que se indique lo contrario. Sin embargo en “Spring Validator” nos referimos a org.springframework.validation.Validator

Al configurar soporte para validacion en Spring, hemos de declarar un Bean especifico (una clase que extienda de org.springframework.validation.beanvalidation.SpringValidatorAdapter que implemente tanto a “Validator” como “Spring Validator” . De forma interna, este Bean utiliza un Validator para dar soporte en operaciones de ambas interfaces (facade). Podemos usar una de estas dos opciones:

javax.validation.beanvalidation.CustomValidatorBean

javax.validation.beanvalidation.LocalValidatorFactoryBean

En la mayoria de casos, usamos “LocalValidatorFactoryBean”, ya que permite recuperar el objeto interno Validator y al mismo tiempo nos permite utilizar el mismo “MessageSource” y ficheros de mensajes que se usan para realizar el resto de la i18n en la aplicacion. De una forma sencilla, configurar el bean “LocalValidatorFactoryBean” seria instanciarlo y retornarlo de esta manera.


/*****/
@Bean methodo de la clase RootContextConfiguration class: 

@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
return new LocalValidatorFactoryBean(); 
} 

El Bean “LocalValidatorFactoryBean” detectara de manera automatica la implementacion de Bean Validation dentro del classpath, si se trata de Hibernate Validator o de otra implementacion, y usara javax.validation.ValidatorFactory, como factoria por detras. No es necesario configurar el fichero de validacion “META-INF/validation.xml”. Aunque a veces, existen mas de un proveedor de Bean Validation en el classpath (un ejemplo seria al ejecutar la aplicacion dentro de un AS como GlashFish o WebSphere).

En estos casos, no sabemos a ciencia cierta, cual es el proveedor de Bean Validation que seleccionara Spring, que incluso puede variar de una vez a otra. En este caso es recomendable establecer el proveedor de forma manual.


/****/
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setProviderClass(HibernateValidator.class); 
return validator; 
} 

La unica pega de realizar esta configuracion es que necesitamos que la dependencia Hibernate Validator se realize en tiempo de compilacion en lugar de runtime. Esto sobrecarga de mensajes en tiempo de compilacion, en los que nuestro IDE, puede resaltar nuestro codigo con sugerencias a clases que no son las que hemos de usar. Para evitar esto, es posible cargar las clases de manera dinamica, lo que tiene como contrapartida que cualquier error en declaracion de codigo no se detectara en tiempo de compilacion.

/******/
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
throws ClassNotFoundException 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setProviderClass(Class.forName( 
"org.hibernate.validator.HibernateValidator" 
)); 
return validator; 
}

Establecer la clase de Bean Validation provider, no es necesario en el contenedor de Servlet Tomcat, no aplicaremos esta tecnica.

2.2. Configurar Mensajes de error de validacion y su Localization

Mas adelante, veremos como añadir constraints a nuestras clases y entidades. Cuando hacemos esto, es posible indicar un mensaje de error que se asocia a cada constraint o bien un codigo de error. De esta forma, permitimos que dicho mensje de error sea posible de internazionalizar antes de ser mostrado al usuario. Por defecto la internacionalizacion en Bean Validation utiliza bundle files de tipo “ValidationMessages.properties” , “ValidationMessages_[language].properties” , “ValidationMessages_[language]_[region].properties”.... Estos ficheros deben estar en el classpath (/WEB-INF/classes ). Con la implementacion de Bean Validation 1.1, es posible sin embargo, crear nuestro propia internacionalizacion mediante javax.validation.MessageInterpolator .De cualquier forma, en cada caso debemos indicar una la Locale que debe usar el Validator cada vez que este se activa. Spring, nos facilita la tarea de crear nuestro propio “MessageInterpolator” y elimina el tener que preocuparse de pasar cada vez la Locale. Lo que necesitamos es establecer MessageSource en el “LocalValidatorFactoryBean” que declaramos dentro de RootContextConfiguration de manera que de forma automatica provee un interpolator para el MessageSource en concreto:

/*****/
... 
@Bean 
public MessageSource messageSource() 
{ 
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 
messageSource.setCacheSeconds(-1); 
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name()); 
messageSource.setBasenames( 
"/WEB-INF/i18n/titles", "/WEB-INF/i18n/messages", 
"/WEB-INF/i18n/errors", "/WEB-INF/i18n/validation" 
); 
return messageSource; 
} 
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setValidationMessageSource(this.messageSource()); 
return validator; 
} 
... 
/*****/


Una vez configurado “LocalValidatorFactoryBean” para usar nuestro “MessageSource” , podemos crear mensajes de validacion segun la Locale de manera correcta en tiempo de ejecucion.

2.3. Usar Method Validation Bean Post-Processor

El concepto de Spring bean post-processors se usa para configurar, personalizar y si necesario reemplazar aquellos beans que existen en nuestra configuracion antes del que el contenedor complete su proceso de arraque. Configurado el org.springframework.beans.factory.config.BeanPostProcessor sus implementaciones se ejecutan antes de que un bean se inyecte dentro de otros beans que dependen de el, por ejemplo:

a) AutowiredAnnotationBeanPostProcessor es un bean del framework que se crea automaticamente cuando configuramos Spring. Controla las anotaciones @Autowire y @Inject y de inyectar dichos valores.

b) InitDestroyAnnotationBeanPostProcessor controla implementaciones de InitializingBean (o metodos anotados con @PostConstruct ) y las implementaciones de DisposableBean (o metodos anotados con @PreDestroy) y ejecuta dichos metodos en la fase apropiada de su ciclo de vida.

c) Algunos post-processors pueden incluso reemplazar el bean. El caso de AnnotationBeanPostProcessor se encarga de buscar aquellos bean con metodos @Async y reemplaza dichos beans con proxies de manera que dichos metodos puedan ser llamados de manera asincrona. La mayoria de los bean post-procesors que necesitamos, como los descritos anteriormente, se crean de manera automatica. Sin embargo, para dar soporte a la validacion de los argumentos de metodos y sus valores de retorno necesitamos crear un org.springframework.validation.beanvalidation .MethodValidationPostProcessor, para que se generen los proxy de la ejecucion los metodos validados. Esta fase no es tan sencialla como la de instanciar un bean MethodValidationPostProcessor ya que por defecto utiliza el validation provider del classpath (sin haber asignado nuestro MessageSource). En su lugar, podemos configurarlo para que use LocalValidatorFactoryBean que creamos anteriormente.

@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() { ... } 
@Bean 
public MethodValidationPostProcessor methodValidationPostProcessor() 
{ 
MethodValidationPostProcessor processor = 
new MethodValidationPostProcessor(); 
processor.setValidator(this.localValidatorFactoryBean()); 
return processor; 
} 
@Bean 
public ObjectMapper objectMapper() { ... } 

Este MethodValidationPostProcessor cotrola las clases que se anotan con “@org.springframework .validation.annotation.Validated” o “@javax.validation.executable.ValidateOnExecution” de forma que crea un proxy de dichas clases, de forma que la validacion de los parametros de los metodos se realiza “antes” de la ejecucion del metodo. Y para el valor de retorno, la validacion ocurre justo despues de la ejecucion del metodo.

2.4. Configurar que Spring MVC use el mismo Bean Validator

A diferencia de “MethodValidationPostProcessor” que creamos anteriormente que usa una instancia de Validator, el controlador de objetos form de Spring MVC y la validacion de parametros de los metodos, usan una instancia de Spring Validator. Esto soporte, proveyendo de argumentos de tipo Errors a los metodos que esperan el parametro @Valid ya que la interfaz Errors es mas sencilla de usar que una coleccion de ConstraintViolations. Afortunadamente, “LocalValidatorFactoryBean” implementa ambos interfaces, por defecto Spring MVC, crea una instancia de Spring Validator aparte que oculta la que se creo en la raiz de lel root application context.

Para modificar esta configuracion por defecto, es necesario modificar la clase “ServletContextConfiguration” dicha clase que hereda de “WebMvcConfigurerAdapter”, sobrecargar el metodo getValidator y devolver el validato que habiamos creado en el root application context.


@Inject SpringValidatorAdapter validator; 
... 
@Override 
public Validator getValidator() 
{ 
return this.validator; 
} 

Con este cambio, Spring MVC usara el Validator que configuramos, para validar el controlador deseado, los parametros de sus metodos y valores de retorno.

3. Añadir anotaciones de validacion a nuestros Beans

Para poder realizar Bean Validation, la aplicacion Spring trabaja con 2 tipos de bean principalmente:

a) POJOs o JavaBeans -es el caso de entidades y objetos de formulario que aparecen como parametro en un metodo o son el resultado que devuelve.

b) Beans propios de Spring como @Controller y @Service que usan los anteriores en sus metodos y tipos de retorno.

Ambos tipos de bean utilizan anotaciones constraint de Bean Validation, pero de distinta manerja. En esta seccion veremos como aplicar annotation constraints a POJO,s. Mas adelante lo haremos sobre Beans propios de Spring.

3.1. Comprender las Built-in Constraint Annotations

Aunque es posible definir nuestras propias constraints, el API de Bean Validation trae varias annotation constraints predefinidas, que muy a menudo es suficientemente completo para nuestro uso. Dichas constraints vienen en el paquete javax.validation.constraints .

Aqui mostramos la mayoria de ellas:

1) @Null — Se aplica sobre cualquier tipo de objeto y asegura que el elemento anotado es null

2) @NotNull — Tambien se aplica sobre cualquier tipo de objeto. Se asegura de que el valor es No null.

3) @AssertTrue y @AssertFalse — Se asegura que el valor anotado es true en la primera y false en la segunda. Por ello el parametro anotado o el valor de retorno debe ser de tipo Boolean. Un Boolean con valor null se considera valido en ambas constraints por lo que han de acompañarse de @NotNull si no se acepta dicho valor.

4) @DecimalMax — Declara el valor maximo para un tipo numerico. Puede anotar atributos, parametros de metodo, y metodos de tipos BigDecimal , BigInteger , CharSequence ( String ), byte , Byte , short , Short , int , Int , long , and Long . Los tipos double , Double , float , and Float, no son soportados debido a la cuestion de precision. Una CharSequence se pasa a decimal antes de aplicar la validacion y si se trata de un valor null, se considera valido. Ademas la anotacion acepta un atributo “inclusive=true”, que inidica si la comprobacion debe realizarse de forma inclusiva (menor o igual que) o exclusiva (menor que).

5) @DecimalMin — Igual que la anotacion anterior aplicado al valor menor.

6) @Digits — Se utiliza para asegurar que el elemento anotado es parseable a number (si se trata de una CharSequence) y a continuacion comprueba de que tipo se trata (si es un CharSequence , BigDecimal , BigInteger , byte , Byte , short , Short , int , Int , long , o Long ). El atributo obligatorio “integer” indica el numero maximo numero de digitos enteros en la secuencia, mientras que el atributo “fraction” indica el numero maximo de digitos tras el punto. Los valores nulos son aceptados.

7) @Future — Asegura que el elemento Date o Calendar, contiene un valor mayor al instante actual, ya sea cercano o lejano. Los valores null son aceptados.

8) @Past — Asegura que el elementot Date and Calendar, contiene un valor inferior al instante actual. Valores nulos son aceptados.

9) @Max y @Min — Semejante a @DecimalMax y @DecimalMin, pero no puede aplicarse sobre elementos CharSequence y no tienen el atributo “inclusive”, ya que son siempre inclusive (menor o igual que). Los elementos de valor “null” se consideran validos.

10) @Pattern — Esto nos permite declarar una expresion regular hacia un elemento de tipo CharSequence ( String ) debe cumplir, y considera los valores null como validos. Acepta un flag adicional que soporta un array de elementos del enum Pattern.Flag. Los valores soportados son: Patter.Flag. 1) CANON_EQ — Equivalentes canonicalmente 2) CASE_INSENSITIVE — Mayuscula o minuscula indiferentemente 3) COMMENTS — Permite que existan espacios en blanco y comentarios (“aaa”) dentro del patron 4) DOTALL — Activa el modo todocon puntos 5) MULTILINE — Activa el modo multiline 6) UNICODE_CASE — Activa el modo Unicode 7) UNIX_LINES — Activa el modo unix (CRLF)

11) @Size — Establece los limites inclusivos de @Max y @Min a la longitudo de la CharSequence ( String ), el numero de valores de la Colleccion, el numero de entradas en un Map, o el numero de elelemntos de un array de cualquier tipo.

3.2. Atributos comunes de Annotation Constraints

Como vemos existe una gran cantidad de constraints que podemos usar. Ademas de eso, existen atributos especificos de dichas anotaciones que ya hemos comentado, toda anotacion de constraint tiene ademas el siguiente numero de atributos opcionales. Los cuales deben estar tambien presentes en una constraint propia hayamos cread.

1) message — Este atributo indica que mensaje debe mostrarse al usuario. Si el mensaje esta contenido entre llaves ( message="{employee.firstName.notBlank}" ), el contenido representa un codigo que debe ser localizado. Por defecto apunta a un codigo de mensaje que es diferente para cada tipo de constraint. 2) groups — Se trata de un array de Class que indica que grupo de validacion o grupos pertenece esta constraint. Por defecto si el array esta vacio, esto indica que la constraint pertenece a su grupo por defecto. Mas adelante se explicara que son los grupos de validacion. 3) payload — Otro array de Class, dichas clases deben heredar de javax .validation.Payload . Los Payloads aportan meta-informacion al proveedor de validacion (al Constraint Validator), que debe realizar dicha validacion. Esto hace que los payloads no puedan migrar de un proveedor a otro en las anotations constraints que vienen por defecto (ya que el API no declara typos de payload), sin embargo pueden ser utiles a la hora de construir nuestras propias constraints. Podemos usar los payloads para cualquier cosa dentro de nuestra propia constraint (aportarnos cierta informacion extra).

Para finalizar, todas estas annotation constraints declararn una anotation interna: @List que nos permite aplicar varias constraints encadenadas, para un elemento en concreto. Por ejemplo, podemos anotar un elemento con varios @Max mediante @Max.List.

3.3. Ejemplo de Annotation Constraints

Para comprender mejor el uso basico de constraints, usaremos el ejemplo del principio de la clase “Customer”, se trata de un POJO y muestra una validacion de las reglas de negocio mediante annotations.


public class Customer 
{ 
private long id; 
@NotNull(message = "{validate.customer.firstName}") 
private String firstName; 
@NotNull(message = "{validate.customer.lastName}") 
private String lastName; 
private String middleName; 
@NotNull(message = "{validate.customer.governmentId}") 
private String governmentId; 
@NotNull(message = "{validate.customer.birthDate}") 
@Past(message = "{validate.customer.birthDate}") 
private Date birthDate; 
@NotNull(message = "{validate.customer.gender}") 
private Gender gender; 
@NotNull(message = "{validate.customer.badgeNumber}") 
private String badgeNumber; 
@NotNull(message = "{validate.customer.address}") 
private String address; 
@NotNull(message = "{validate.customer.city}") 
private String city; 
@NotNull(message = "{validate.customer.state}") 
private String state; 
@NotNull(message = "{validate.customer.phoneNumber}") 
private String phoneNumber; 
@NotNull(message = "{validate.customer.email}") 
@Pattern( 
regexp = "^[a-z0-9`!#$%^&*'{}?/+=|_~-]+(\\.[a-z0-9`!#$%^&*'{}?/+=" + 
"|_~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?)+(\\.[a-z0-9]" + 
"([a-z0-9-]*[a-z0-9])?)*$", 
flags = {Pattern.Flag.CASE_INSENSITIVE}, 
message = "{validate.customer.email}" 
) 
private String email; 
 
// mutators and accessors 
} 

Deberiamos tener en cuenta algunos puntos:

a) La mayoria de los atributos estan anotados con @NotNull, b) No existe sustitucion para la linea “trim().length() > 0”,lo que puede volverse un problema de redundancia de codigo rapidamente. c) La expresion regular para validar el e-mail es bastante grande y puede volverse engorrosa si se usa en varias partes. d) birthDate is se comprueba para verificar que se encuentra en el pasado, no para comprob ar que es mayor de edad, ademas el elemento debe ser de un tipo Date previo a Java 8.

De esta manera, podemos realizar validaciones incluso crear las nuestras propias. Sin embargo hay que tener en cuenta que no es valido para todo tipo de validacion. Ya que a menudo necesitamos comprobar que existe el attributo (acceder a base de datos u otro), y esas tareas requieren una validacion mas manual.

3.4. La annotation @Valid para realizar Recursive Validation

Hasta ahora hemos ido anotando atributos sencllos como Strings mediante las validation constraints. Que ocurre en el caso de que el elemento a validar es un tipo complejo que contiene a su vez elementos anotados con constraints?

En este ejemplo:

public class Helicopter 
{ 
@NotNull 
private String name; 
@NotNull
private AirPort origin; 
@NotNull 
private AirPort destination; 
@NotNull 
private List<Person> crew; 
@NotNull 
private Person engineer; 
@NotNull 
private Person pilot; 
// mutators and accessors 
} 

Las clases AirPort y Person de este ejemplo son POJOs con sus propios atributos que estan a su vez anotados con validation constraints. Estos objetos anidados no se validan automaticamente. Para asegurarnos de que se validan, debemos anotar estos atributos como @Valid, lo cual indica que un atributo, parametro, o metodo debe validarse en cascada. that a field, parameter, or method (return value) should result in cascading validation.


public class Helicopter 
{ 
@NotNull 
private String name; 
@NotNull
@Valid private AirPort origin; 
@NotNull 
@Valid private AirPort destination; 
@NotNull 
@Valid private List<Person> crew; 
@NotNull 
@Valid private Person engineer; 
@NotNull 
@Valid private Person pilot; 
// mutators and accessors 
} 

Si AirPort o Person, contiene atributos que a su vez estan marcados con @Valid, la validacion continua en profundidad hasta llegar a comprobar todos los valores.

Existe un riesgo, sin embargo, cuando el validator detecta un bucle infinito causado por ejemplo debido a “referencias ciclicas”, de manera que termina la validacion sin detectar error despues de que el circulo de referencias le alcanza.

3.5. Validation Groups

Los grupos de validacion nos permiten activar y desactivar ciertas constraints segun el grupo al que pertenecen y segun que grupos estan activos en ese momento. Esto es muy similar a los Bean Definition Profiles de Spring. Un grupo se representa a traves de cualquier interfaz de marcado. La interfaz debe de no contener ninguna constantes o metodos ya que no sera utilizados. En su lugar, el objeto de Classe interfaz, representa al grupo cuando se define una constraint. A continuacion, en tiempo de validacion, el Validator aplica unicamente aquellas constraints cuyo grupo de Class se indica cuando se realizo la llamada a uno de los metodos: validate, validateProperty o validateValue

Por ejemplo, consideremos una entrada en varios pasos a partir de un UI, en la cual los atributos se van rellenando en cada pagina. Podriamos desear validar que los valores de atributos sean los correctos en cada paso, pero tambien podriamos querer almacenar todos esos valores en un mismo objeto form. Mediante los groups, resulta sencillo:


public interface UiScreen1 { } 
public interface UiScreen2 { } 
public interface UiScreen3 { } 

public class Form 
{ 
@NotNull(groups = UiScreen1.class) 
private String field1; 
@NotNull(groups = UiScreen2.class) 
private String field2; 
@NotNull(groups = UiScreen2.class) 
private String field3; 
@NotNull(groups = UiScreen3.class) 
private String field4; 
// mutators and accessors 
} 

A continuacion, cuando debamos validar, solo es necesario pasar el grupo de class apropiado a cada llamada de Validator, y se aplicaran las constraints que corresponden a dichos grupos. Si usamos javax.validation .groups.Default, si ademas queremos evaluar las constraints sin ningun grupo predefinido.

/*esto seria */
// en metodo para paso 1 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class) 
// para el metodo del paso 2 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class, UiScreen2.class) 
// en metodo para el paso 3 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class, UiScreen2.class, UiScreen3.class) 

Si una constraint no declara ningun grupo, se toma el grupo por defecto. De la misma manera, si una llamada a validate , validateProperty , o validateValue no contiene ningun grupo aplicara tambien el grupo por defecto.

Los grupos de Validation son ademas utiles para aplicar una misma constraint de manera distinta segun el grupo. Asi @Size.List y @Size, por ejemplo, es posible indicar que un elemento de tipo String debe tener una longitud determinada si se valida por un grupo y otra longitud si se valida por otro grupo (o grupos).

/**ejemplo en el que se aplica una constraint de distintas formas **/
public class BusinessObject 
{ 
@Size.List({ 
@Size(min = 5, max = 100, groups = {Default.class, Group1.class}), 
@Size(min = 20, max = 75, groups = Group2.class) 
}) 
private String value; 
// mutators and accessors 
} 

Como suele ser, Spring simplifica el uso de grupos de validation. En vez de tener que acceder al validador directamente, podemos establecer en una anotacion que grupos deben estar activos al validar un elemento. Veremos mas acerca de esto en la siguiente seccion.

3.6. Comprobar la validez de una Constraint en tiempo de compilacion

En el lenguaje Java existen reglas acerca de que anotaciones podemos usar y donde, establecido mediante java.lang.annotation.ElementType y los valores establecidos a traves de @java.lang.annotation.Target para una definicion particular de anotacion. Sin embargo, las reglas acerca de donde es posible aplicar las constraints de validacion son mucho mas complejas que las que se soportan de forma nativa. Por ejemplo, las anotaciones de constraint pueden aplicarse a ElementyType.METHOD (y otras) en tiempo de compilacion, pero esto pasa por encima el hecho de que las anotaciones de constraint son solo validas en metodos de instancia y no en metodos static (es una diferencia que ElementType no tiene en cuenta). De la misma manera, las constraints solo son validas en metodos de instancias y no en metodos static, sin embargo el compilador no puede capturar esta diferencia tampoco. Aun mas importante que esto, las distintas constraints se limitan a distintos tipos (no es posible usar @Future sobre Strings por ejemplo), y necesitas una manera de asegurarte que aplicamos estas constraints de forma correcta.

El API “Hibernate Validator” dispone de un procesador de anotaciones que en tiempo de compilacion toma control de cierta parte y evita que dicho codigo compile, si las restricciones explicadas anteriormente no se cumplen. Esto facilita, poder aplicar dichas “constraints de validacion” de manera mas sencilla ya que sino el compilador dara error, lanzando una javax.annotation.ConstraintDeclarationException . Para disponer del annotation processor, necesitamos añadir las siguientes dependencias:

 
org.hibernate 
hibernate-validator-annotation-processor 
5.1.0.Final 
compile 
true 
 

La razon por la que esta dependencia se marca como opcional es que Hibernate Validator no la necesita en tiempo runtime. Solo se llama en tiempo de compilacion, de manera que se detecta el anotation processor existente. La parte positiva de hacerlo asi es que el processor se aplica de forma automatica en la fase build de Maven y en la compilacion desde el IDE. La parte negativa es que las clases se encuentran en el classpath y nuestro IDE nos las ofrecera como opcion.

Existen otras formas de instalar annotation processors dentro de Maven y de nuestro IDE. Por ejempo, es posible añadir la dependencia dentro del plug-in del compilador a usar, en lugar de dentro de las dependencias del proyecto, lo que evita que aparezcan en el classpath, pero nos fuerza a separar anotation processor de nuestro IDE.