2011-05-09 13 views
10

A menudo encuentro la necesidad de validar un conjunto de condiciones, y en lugar de fallar anticipadamente (devolver falsas o lanzar una excepción cuando no se cumple la primera condición), necesito agregar los resultados e informar al individuo fallasExcepciones agregadas

Actualmente estoy usando una lista con entradas personalizadas (básicamente una entrada consiste en el tipo de falla y algún mensaje informativo) o algún tipo de observador (que también agrega las fallas), pero tengo la sensación que esto debería ser un problema común y que debería haber algún patrón existente para resolver esto.

Respuesta

9

Sí, es un problema común, y ambos enfoques son buenos.

javax.validation.Validator, que es el estándar para la validación de java, utiliza el primero. Devuelve un Set de ConstraintViolations s

Si se ajusta a su caso, le recomendaría usar javax.validation en lugar de algo personalizado. Es una especificación con múltiples proveedores, uno de los cuales es hibernate-validator (no es necesario usar hibernate para usar el proyecto de validación)

1

No creo que necesite una solución compleja. Cuando tengo que hacer esto, por lo general acaba de escribir algo como:

List<String> errors=new ArrayList<String>(); 
... 
if (foo<0) 
    errors.add("Bad foo"); 
if (!bar.contains(plugh)) 
    errors.add("No plugh in bar"); 
... etc, whatever other errors ... 
... then at the bottom ... 
if (errors.size()>0) 
{ 
    ... throw exception, display errors, whatever ... 
} 
... else celebrate and get on with it ... 

O si sé que todo lo que voy a hacer con los errores es la pantalla un mensaje grande, yo sólo puede hacer que el campo de error de una cadena y seguir agregando mensajes en cualquier formato.

1

Utilizo la siguiente clase para recopilar y mostrar varias excepciones. Solo hace uso de Java estándar.

package util; 

import java.io.ByteArrayOutputStream; 
import java.io.IOError; 
import java.io.IOException; 
import java.io.PrintStream; 
import java.util.*; 

/** 
* This abstract class is to be used for Exception generating by a collection of causes. 
* <p /> 
* Typically: several tries take place to do something in different ways and each one fails. We therefore 
* have to collect the exceptions to document why it was not possible at all to do the thing. 
*/ 
public abstract class AggregateException extends Exception 
{ 
    /** A generator of random numbers */ 
    private final static Random rand = new Random(); 

    /** The causes of the exception */ 
    private final Vector<Throwable> causes; 

    /** A (reasonably unique) id for this exception. Used for a better output of the stacktraces */ 
    private final long id = rand.nextLong(); 

    /** 
    * @see Exception#Exception(String) 
    * @param message 
    */ 
    public AggregateException(String message, Collection<? extends Throwable> causes) 
    { 
     super(message); 
     this.causes = new Vector<Throwable>(causes); 
    } 

    /** 
    * Prints this throwable and its backtrace to the specified print stream. 
    * 
    * @param s <code>PrintStream</code> to use for output 
    */ 
    public void printStackTrace(PrintStream s) { 
     synchronized (s) { 
      s.println(this); 
      StackTraceElement[] trace = getStackTrace(); 
      for (int i=0; i < trace.length; i++) 
       s.println("\tat " + trace[i]); 

      final Throwable ourCause = getCause(); 
      if (ourCause != null) 
       throw new AssertionError("The cause of an AggregateException should be null"); 

      for (int i = 0; i<causes.size(); i++) 
      { 
       final Throwable cause = causes.get(i); 
       s.println(String.format(
         "Cause number %s for AggregateException %s: %s ", 
         i, 
         getId(), 
         cause.toString() 
       )); 

       final ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); 
       final PrintStream ps = new PrintStream(byteArrayOS); 
       cause.printStackTrace(ps); 
       ps.close(); 
       final String causeStackTrace = byteArrayOS.toString(); 
       int firstCR = causeStackTrace.indexOf("\n"); 

       s.append(causeStackTrace.substring(firstCR == -1 ? 0 : firstCR+1)); 
      } 
     } 
    } 

    @Override 
    public String toString() 
    { 
     return String.format(
       "%s. AggregateException %s with %s causes.", 
       super.toString(), 
       getId(), 
       causes.size() 
         ); 
    } 

    @Override 
    public Throwable initCause(Throwable cause) 
    { 
     if (cause != null) 
      throw new AssertionError("The cause of an AggregateException must be null"); 

     return null; 
    } 

    /** 
    * 
    * @return {@link #id} 
    */ 
    private String getId() 
    { 
     return String.format("%xs", id); 
    } 

    /** 
    * Test class 
    */ 
    public static class TestException extends AggregateException 
    { 
     /** 
     * Constructor 
     * @param message 
     * @param causes 
     */ 
     public TestException(String message, Collection<? extends Throwable> causes) 
     { 
      super(message, causes); 
     } 

     /** 
     * Test program 
     * 
     * @param notused 
     * @throws AggregateException 
     */ 
     public static void main (final String[] notused) throws AggregateException 
     { 
      final List<Error> causes = new LinkedList<Error>(); 
      causes.add(new OutOfMemoryError()); 
      try 
      { 
       generateIOError(); 
      } 
      catch (final Error th) 
      { 
       causes.add(th); 
      } 

      final AggregateException ae = new TestException("No test has sucessed", causes); 

      throw ae; 
     } 

     /** 
     * For test: generate an IOError caused by an IOException 
     */ 
     private static void generateIOError() 
     { 
      try 
      { 
       generateIOException(); 
      } 
      catch (final IOException ioex) 
      { 
       throw new IOError(ioex); 
      } 
     } 

     /** 
     * For test: throws an IOException 
     * @throws IOException 
     */ 
     private static void generateIOException() throws IOException 
     { 
      throw new IOException("xxx"); 
     } 
    } 


} 
+0

Eso no funcionará si alguien más captura su AggregateException y lo vuelve a generar como causa - printStackTrace no se garantiza que se llame de forma recursiva. (Además, te perdiste la sobrecarga PrintWriter). –

Cuestiones relacionadas