Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Need help refactoring an input validation aspect

On Mon, 16 May 2005, David Coppit wrote:

I'm just getting started with AspectJ, and have gotten stuck on
extracting some exception handling concerns. Can anyone point me in the
right direction?

Harold Ossher reminded me that around advice can work in this situation.
(Thanks!) Here's the solution for posterity.

Here's the original code:

  private static int promptForNumber(final BufferedReader stdin) {
    int inputSize = 0;

    boolean inputIsValid = false;
    while (!inputIsValid) {
      try {
        inputSize = Integer.parseInt(stdin.readLine());

        inputIsValid = true;
      } catch (IOException e) {
        System.err.println(
          "Encountered an I/O exception. Exiting.");
        System.exit(1);
      } catch (NumberFormatException e) {
        System.err.println(
          "Invalid number entered. (" + e.getMessage() + ")" );
      }
    }

    return inputSize;
  }

Here's the AspectJ code:

  // Yay! A single, simple call
  private static int promptForNumber(final BufferedReader stdin) {
    return Integer.parseInt(stdin.readLine());
  }

  aspect IOExceptionHandling {
    // Let the exception come out of the method so we can more easily catch it
    // with an around advice.
    declare soft : IOException : call(String BufferedReader.readLine());

    pointcut promptForNumber(): call(String BufferedReader.readLine());

    String around(): promptForNumber() {
      String value = "";

      try {
        value = proceed();
      } catch (org.aspectj.lang.SoftException e) {
        if (e.getWrappedThrowable() instanceof IOException) {
          System.err.println("Encountered an I/O exception. Exiting.");
          System.exit(1);
        }
        else
          // Can this happen?
          throw e;
      }

      return value;
    }

  }

  aspect InputValidation {

    pointcut promptForNumber(BufferedReader stdin):
        call(int Average.promptForNumber(BufferedReader)) && args(stdin);

    // promptForNumber is called by both readData and promptForValues, so
    // only do this check for the former.
    after() returning(int inputSize): promptForNumber(BufferedReader) &&
        !cflow( call(Vector Average.promptForValues(BufferedReader,int)) ) &&
        cflow( call(Vector Average.readData()) ) {
      if (inputSize <= 0)
        throw new NumberFormatException( "The number must be greater than 0.");
    }

    // This advice must follow the previous for precedence to be correct
    // and the thrown exception caught by this advice's exception handler.
    int around(BufferedReader stdin): promptForNumber(BufferedReader) &&
        args(stdin) {
      int value = 0;

      boolean inputIsValid = false;
      while (!inputIsValid) {
        try {
          value = proceed(stdin);

          inputIsValid = true;
        } catch (NumberFormatException e) {
          System.err.println(
            "Invalid number entered. (" + e.getMessage() + ")" );
        }
      }

      return value;
    }

  }

David


Back to the top