Grails Constraint Exception Handling

Exceptions thrown at commit (not save) result in this unfriendly dialog..



Install under STS as noted in the parent page.  Replace the 2 attached files to investigate the "Attempts" described below.  You will need to acquire the autobizlogicxx.jar from the Main Installer.

Commit (vs save) Exceptions

Automated Business Logic performs its processing at commit time, not save time.  In particular, we throw exceptions when Constraints are violated, as illustrated in the next section.

How to run

Show the first Customer, Edit it, and set the Credit Limit to 9.  This will violate the Customer Constraint "balance < creditLimit".  The expectation is to see this in a error area, as is used for Grails Domain Constraints.


Using this suggestion did not work by altering the URLMapping file like this:

// replace default: "500"(view:'/error')
"500"(controller: 'errors', action: 'error')

and providing an ErrorsController like this:

package buslogicdemograils
class ErrorsController {
    def index = { }
    def error = {
        def exception = request['javax.servlet.error.exception']?.cause?.cause
        if (exception) {
            System.out.println("ErrorsController here")

After enabling, when the error fired ("How to run"), the result was a missing page:

404 - resource not avail: http://localhost:8080/BusLogicDemoGrails/customer/index


Code changes to the Customer Controller appeared to disable the entire transaction bracketing - business logic did not run (it fails if updates are issued when not in a transaction).  Enable this by resetting the URLMapping, changing the Customer Controller (~ line 11):

static Boolean useWithTransaction = true

The End User sees a "successful transaction" message (it did succeed since Business Logic failed to fire as explained above).

Before/After Interceptors

Set breakpoints in def error, and uncomment the following in CustomerController:

/* these do not get control on commit exception (either for error, or errors) 

def beforeInterceptor = [action:this.&error, only: 'error']

// defined as a regular method so its private

def afterInterceptor = { model, modelAndView ->

println "after interceptor"



The breakpoint is not hit in the error def.  The end result is the same as shown at the top of the page.