OVal

De Dos Ideas.

OVal es un framework pragmático y extensible para validar cualquier tipo de objetos Java (y no sólo JavaBeans).

Se pueden declarar restricciones usando anotaciones (@NotNull, @MaxLength, etc), POJOs y XML. También se pueden crear restricciones personalizadas, usando clases Java o expresiones en lenguajes de scripting, como JavaScript, Groovy, BeanShell, OGNL o MVEL.

Además de validaciones a nivel de atributos, OVal permite implementar el Diseño Por Contrato, aplicando restricciones a métodos usando la técnica de AOP a través de AspectJ. De esta manera se pueden validar argumentos de un método en tiempo de ejecución.

Contenido

Características

OVal permite:

  • validar objetos de forma simple a demanda
  • especificar restricciones para atributos de una clase, y para métodos getter
  • validar objetos basándose en ciertas anotaciones de EJB3 JPA (como ser todos los campos que necesitan un valor no-nulo)
  • configurar las restricciones a través de anotaciones, POJOs y/o archivos
  • expresar restricciones usando lenguajes de scripting como Groovy, BeanShell y JavaScript
  • crear restricciones personalizadas de forma simple
  • desarrollar nuevos mecanismos para configurar restricciones

OVal y el Diseño por Contratos

OVal nos permite implementar un Diseño Por Contrato (DbC) de manera simple, ya que nos brinda mucha funcionalidad que caracteriza al DbC:

  • especificar restricciones para los parámetros de un constructor que se verifican automáticamente cuando se invoca al constructor (precondición)
  • especificar restricciones para los parámetros de un método que se verifican automáticamente cuando se invoca al método (precondición)
  • requerir cierto estado en un objeto antes de invocar al método (precondición)
  • forzar la validación del objeto luego de haber creado al objeto (invariante)
  • forzar la validación del objeto antes/después de invocar un método del objeto (invariante)
  • especificar restricciones para el valor de retorno de un método que se comprueba automáticamente luego de que se ejecuta el método (postcondición)
  • requerir un estado determinado en el objeto luego de la invocación a un método (postcondición)

Integración con Spring Framework

Es posible integrar OVal con Spring Framework, de manera de interceptar los beans de Spring con el validador de OVal. De esta manera Spring usará AOP para cambiar el comportamiento de los beans interceptados, incorporando las validaciones de OVal.

Para esto usaremos el interceptor net.sf.oval.guard.GuardInterceptor ya provisto por OVal. La configuración es muy simple, y funciona igual que el resto de los Interceptores Con Spring.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

 
 
<!-- El interceptor de OVal que realizará las validaciones. -->
<bean id="ovalGuardInterceptor" class="net.sf.oval.guard.GuardInterceptor" />
 
<!-- interceptamos las clases que nos interesen. Es importante establecer
el parametro proxy-target-class="true". Luego creamos los Pointcuts y
advisors que nos interesen. En este ejemplo interceptamos todas las
clases del paquete com.dosideas.service.
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="objetosDeNegocio"
expression="execution(* com.dosideas.service.*.*(..))"/>
 
<aop:advisor advice-ref="ovalGuardInterceptor"
pointcut-ref="objetosDeNegocio"/>
</aop:config>
 
 
<!-- Este bean de ejemplo será interceptado por OVal y tendrá validaciones -->
<bean id="service.Persona" class="com.dosideas.service.PersonaServiceImpl"/>
 
</beans>

OVal con EHcache en Spring Framework

Para trabajar tanto con Interceptores Con Spring, EhCache y OVal al mismo tiempo debemos configurar los siguientes archivos:

interceptors.xml (donde quedarán configurados los interceptores y OVal)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" default-lazy-init="true">

 
<!-- OVal -->
<bean id="interceptor.ovalGuardInterceptor" class="net.sf.oval.guard.GuardInterceptor" />
 
<!-- Métodos a interceptar -->
<aop:config>
<aop:pointcut id="metodosEnClaseEjemplo"
expression="execution(* com.tm.dosideas.business.ClaseEjemploBo.mostremosUnEjemplo(..))"/>
<aop:pointcut id="metodosParaOvalEnBos"
expression="execution(* com.tm.dosideas.business.*.*(..)) and !execution(* com.tm.dosideas.business.ClaseEjemploBo.*(..))" />
</aop:config>
 
 
<aop:config>
<aop:advisor advice-ref="txAdviceSupports" pointcut-ref="metodosEnConfigurationLog"/>
</aop:config>
 
 
<aop:config proxy-target-class="true" >
<aop:advisor advice-ref="interceptor.ovalGuardInterceptor"
pointcut-ref="metodosParaOvalEnBos"/>
</aop:config>
 
<tx:advice id="txAdviceSupports" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
 
</beans>

Por otro lado, deberemos configurar el archivo de miAplicacion-ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ehcache="http://www.springmodules.org/schema/ehcache"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springmodules.org/schema/ehcache
http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd" default-lazy-init="true">

 
<ehcache:config configLocation="classpath:ehcache.xml"/>
 
<bean id="business.ClaseEjemploBoTarget" class="com.tm.dosideas.business.impl.ClaseEjemploBoImpl">
<property name="claseEjemploDao" ref="dao.ClaseEjemploDao" />
<!-- Este tag es fundamental para indicarle a EhCache
que trabaje con ClaseEjemploBoTarget mediante un proxy y no mediante
una clase. De no poner este tag vamos a tener excepciones tales como
Could not generate CGLIB subclass of class [class $Proxy14]: Commoncauses of this problem
include using a final class or a non-visible class; nested
exception is java.lang.IllegalArgumentException: Cannot subclass final
class class $Proxy14 -->
<aop:scoped-proxy/>
</bean>
 
<ehcache:proxy id="business.ClaseEjemploBo" refId="business.ClaseEjemploBoTarget">
<ehcache:caching cacheName="cacheMostremosUnEjemplo" methodName="mostremosUnEjemplo"/>
</ehcache:proxy>
</beans>

Ver también