Working with Grails

Be transactional

Your business logic will be invoked only in the context of a Hibernate transaction, therefore anything that may modify the data should be transactional. This is a vast topic, thankfully well covered in the Grails documentation and in the Spring documentation.

There are many ways to ensure that a transaction is used: some declarative, some procedural. They are all equally valid: the only thing that matters is that objects be created, changed or deleted in the context of a transaction.

One thing not to do is declare your controller class as transactional. This is because controllers get called many times, and assigning the Transactional annotation to it leads to complete madness; way too many transactions get fired, data gets committed when it really shouldn't, etc... Better to use a transactional service, or to start and commit transactions in your code. You could, if desired, declare individual methods of a controller as transactional, though that may be frowned upon by some Grails purists, who might argue that object manipulation belongs in a service.


Exception handling


If a constraint fails, it might be nice to show a friendly message to the user. By default, the user will see the default error page, which is not really appealing.

Be aware that Automated Business logic exceptions are raised at commit time, not save time.  So, you must catch exceptions at that point.

One possible approach would be to use a programmatic transaction:

try {

    Customer.withTransaction{ status ->

        customerInstance.save()

    }

}

catch(org.springframework.orm.hibernate3.HibernateSystemException ex) {

    if (ex.cause && ex.cause instanceof com.autobizlogic.abl.businesslogicengine.ConstraintException) {

        customerInstance.errors.rejectValue(ex.cause.constraintFailures[0].problemAttributes?.getAt(0), "", 

                        "Constraint was violated : " + ex.cause.constraintFailures[0].constraintMessage)

    }

    else

        throw ex

}


This approach, one of many possible, allows Grails to be notified of the failure, and of which attribute caused the problem, so that it can be highlighted in the UI:



A less flexible, but more general, approach might be to use Grails' response code mapping. By having the following in your UrlMappings.groovy:

"500"(controller: 'constraints', action: 'constraintFailure', exception:
            com.autobizlogic.abl.businesslogicengine.ConstraintException)

you will ensure that, by default, all constraint violations will be routed to the given controller, which might do something like:

class ConstraintsController {
def constraintFailure = {
def ex = request.exception
render "Constraint was violated: " + ex.cause.constraintFailures[0].constraintMessage

This code is obviously very simplistic, but is meant to inspire more sophisticated approaches.


Debugging

You can use STS and its debugging services, but take note of proxy implications.
Comments