3

I needed to display some validation messages received from the service each in its proper place, and I solved it putting the messages in an exception:

class InvalidInputException extends RuntimeException {
    def errors
    InvalidInputException(String s) {
        super(s)
    }

    InvalidInputException(String s, errors) {
        super(s)
        this.errors = errors
    }
}

That way, I could throw the exception sending the errors:

if (errors) {
    throw new InvalidInputException("There were some errors", errors)
}

.. and then I deal with the errors later in the controller, after catching the exception:

...
catch (InvalidInputException e) {
    if (e.errors) {
        // set them up to display appropriately
    }
    // render the view
}

Now, I've read somewhere that Groovy's exceptions can cost too much, so... is this too bad? What problems may I encounter putting additional data in an Exception?

It's much easier than fiddling with returned error messages, and the code is much shorter.

Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107
  • 4
    Looks ok to me... Where did you read that _"Groovy's exceptions can cost too much"_? Also, what is your definition of _"too much"_? – tim_yates Jul 12 '13 at 12:52
  • 3
    The idea that an exception costs too much seems odd to me. An exception is exceptional. If you are at the point where throwing exceptions (they ARE expensive, also in plain java) has an impact on your performance, either you are doing something really badly (throwing too many exceptions) or you are doing so good that you probably can afford a redesign to work around the problem. – Luis Muñiz Jul 12 '13 at 13:16
  • @tim_yates I think the OP wanted to say what loteq says about being expensive. This is discussed [here](http://stackoverflow.com/questions/299068/how-slow-are-java-exceptions), for example. –  Jul 12 '13 at 14:24
  • Well, I guess it's alright then, because that flow is indeed exceptional -- the input has errors, normally it shouldn't. – Elias Dorneles Jul 12 '13 at 14:26

1 Answers1

2

If you are concerned about the performance of exceptions in Java, I suggest you to look at this other question.

If you not create a exception, the other possibility is to make your service return an object that represents the result of this flow. Something like:

class MyServiceResult {
  List<String> errorCodes = [] //codes for i18n

  void addErrorCode(String errorCode) {
    errorCodes << errorCode  //add error to list 
  }

  boolean isValid() {
    return (!(errorCodes.size() > 0)) //if we have errors then isn't valid.
  } 

  List<String> getErrorCodes() {
    return errorCodes.asImmutable()
  } 

}

And just use it in your service method

class MyService {
  MyServiceResult someMethod() {
    MyServiceResult result = new MyServiceResult()
    ...
    result.addErrorCode('some.key.here')
    ...
    return result
  }
}

class MyController {
  def myService
  def action() {
    MyServiceResult result = myService.someMethod()
    if(!result.isValid()) {
      //handle errors
    }
  }
}

But it's important to say that it can be 2x slower than creating an exception. You can check all details in this post.

Community
  • 1
  • 1
  • 1
    Transactions, if there is any, will not be rolled back if `RuntimeException` or `Error` is not thrown from service layer. :) – dmahapatro Jul 12 '13 at 17:03
  • Good catch! If you need more control, you can make your service not transactional and start one manually. –  Jul 12 '13 at 17:18