2009-11-27 9 views
5

Esta es la forma típica de lograr este objetivo:¿Cómo puedo colocar restricciones de validación en los parámetros de entrada de mi método?

public void myContractualMethod(final String x, final Set<String> y) { 
    if ((x == null) || (x.isEmpty())) { 
     throw new IllegalArgumentException("x cannot be null or empty"); 
    } 
    if (y == null) { 
     throw new IllegalArgumentException("y cannot be null"); 
    } 
    // Now I can actually start writing purposeful 
    // code to accomplish the goal of this method 

Creo que esta solución es feo. Sus métodos se llenan rápidamente con un código repetitivo que verifica el contrato válido de parámetros de entrada, oscureciendo el núcleo del método.

Aquí es lo que me gustaría tener:

public void myContractualMethod(@NotNull @NotEmpty final String x, @NotNull final Set<String> y) { 
    // Now I have a clean method body that isn't obscured by 
    // contract checking 

Si esas anotaciones se ven como JSR 303/Bean Validation Spec, es porque ellos prestado. Desafortunadamente, no parecen funcionar de esta manera; están destinados a anotar variables de instancia, y luego ejecutar el objeto a través de un validador.

¿Cuál de las many Java design-by-contract frameworks proporciona la funcionalidad más cercana a mi ejemplo de "me gustaría tener"? Las excepciones que se lanzan deben ser excepciones de tiempo de ejecución (como IllegalArgumentExceptions) para que la encapsulación no se rompa.

Respuesta

5

Si está buscando un mecanismo completo de diseño por contrato, eche un vistazo a algunos de los proyectos enumerados en el Wikipedia page for DBC.

Si buscas algo más simple, puedes mirar la clase Preconditions de las colecciones de google, que proporciona un método checkNotNull(). Para que pueda volver a escribir el código que envió a:

public void myContractualMethod(final String x, final Set<String> y) { 
    checkNotNull(x); 
    checkArgument(!x.isEmpty()); 
    checkNotNull(y); 
} 
+0

Preconditions.checkArgument (! X.isEmpty()). –

+1

Aha, siempre es útil para que el creador de la biblioteca a la mano :) –

0

Esto no responde directamente a su pregunta, pero creo que parte de su problema es que se está exagerando la validación. Por ejemplo, se puede sustituir la primera prueba con:

if (x.isEmpty()) { 
    throw new IllegalArgumentException("x cannot be empty"); 
} 

y se basan en Java para lanzar una NullPointerException si es xnull. Solo necesita modificar su "contrato" para decir que se lanza NPE para ciertos tipos de situaciones de "usted me llamó con parámetros ilegales".

0

Jared le indicó varios frameworks que agregan soporte para DBC a Java.
Lo que encontré que funciona mejor es: simplemente documente su contrato en JavaDoc (o cualquier marco de documentación que utilice; Doxygen tiene soporte para etiquetas DBC).
Tener su código ofuscado por muchos bloqueos y verificaciones de sus argumentos no es realmente útil para tu lector La documentación es

+1

El problema es cuando se ignora, o si se olvida, una de las condiciones previas, a continuación, theres ninguna garantía de que el comportamiento de su va a conseguir. En el mejor de los casos, es posible que obtenga un NPE, en el peor, terminará con una excepción al azar mucho más tarde sin tener idea de por qué ocurrió. –

+0

@Jared Acepto. Pero generalmente no hay mejor manera. O traes un marco pesado y tomas todos los gastos generales de aprendizaje y ofuscación o te apegas a él. Si realmente quiere usar DBC, es mejor que tenga un lenguaje que lo soporte de forma nativa. – pmr

2

He visto una técnica por Eric Burke que es más o menos como la siguiente. Es un uso elegante de las importaciones estáticas. El código dice muy bien.

Para tener la idea, aquí está la clase Contract. Aquí es mínimo, pero se puede completar fácilmente según sea necesario.

package net.codetojoy; 

public class Contract { 
    public static void isNotNull(Object obj) { 
     if (obj == null) throw new IllegalArgumentException("illegal null"); 
    } 
    public static void isNotEmpty(String s) { 
     if (s.isEmpty()) throw new IllegalArgumentException("illegal empty string"); 
    } 
} 

Y aquí hay un ejemplo de uso. El método foo() ilustra las importaciones estáticas:

package net.codetojoy; 

import static net.codetojoy.Contract.*; 

public class Example { 
    public void foo(String str) { 
     isNotNull(str); 
     isNotEmpty(str); 
     System.out.println("this is the string: " + str); 
    } 

    public static void main(String[] args) { 
     Example ex = new Example(); 
     ex.foo(""); 
    } 
} 

Nota: al experimentar, observar que there may be a bug alrededor de hacer esto en el paquete por defecto. Ciertamente he perdido células cerebrales al intentarlo.

+1

Olvidé mencionar que hay una ventaja sutil al lanzar una excepción IllegalArg contra un NullPointer. En el caso del primero, el autor de la API claramente le está diciendo algo sobre el contrato. (Es decir, se pregunta si está tratando con un error.) –

0

me gustaría utilizar parámetros Anotaciones, reflexión y una clase de validador genérico para crear una instalación de toda la aplicación. por ejemplo, puede codificar un método de clase como:

.. myMethod (@notNull cadena x, @notNullorZero cadena y) {

if (Validator.ifNotContractual(getParamDetails()) { 
    raiseException.. 
    or 
    return .. 
} 

}

Los métodos de la clase están "marcados arriba" para anotar sus requisitos de contrato. Usa la reflexión para descubrir automáticamente los parámetros, sus valores y anotaciones. Envíelo todo a una clase estática para validar y dejarte saber el resultado.

1

hay un pequeño paquete de Java Argument Validation, implementado como Llanura de Java. Viene con varias verificaciones/validaciones estándar. Y para aquellos casos en que alguien necesita sus propias validaciones más específicas, viene con algunos métodos de ayuda. Para validaciones que ocurren varias veces, simplemente extienda la interfaz ArgumentValidation, con la suya Y cree la clase de implementación que se extiende desde la clase ArgumentValidationImpl.

+0

Viene con algunos ejemplos, para que funcione. http://java-arg-val.sourceforge.net/usage.html (2 ejemplo en esta página, y también 3 en el Java Doc (referencia a ellos en la parte superior de la página en cuestión) – Verhagen

0

No es una solución totalmente funcional, pero JSR-303 tiene una propuesta de method-level validation extension. Debido a que es solo una propuesta de extensión, las implementaciones de JSR-303 pueden ignorarla. Encontrar una implementación es un poco más complicado. No creo que Hibernate Validator lo admita todavía, pero creo que agimatec-validation tiene soporte experimental. No he utilizado tampoco para este fin, así que no sé qué tan bien funcionan. Sin embargo, me gustaría averiguar si alguien lo intenta.

Cuestiones relacionadas