Tuesday, January 05, 2010

Groovy Truth

Groovy had its truth. Groovy expanded on what Java allows to use in various control structures. While Java allows only boolean expression in if and while control structures, Groovy relaxed the requirement. In Groovy you can use objects in if and while expressions. Only a non-null and non-empty string will evaluate to true. A non-empty collection will evaluate to true. Non zero numbers will evaluate to true.

With Groovy 1.7, Groovy Truth got better. You can now customize the Truth based on your requirement. This can be done by implementing boolean asBoolean() method. Implement the method on any object and logic defined in the method will be used to evaluate. Look at the following example


class Account {
     ...
     String status
     boolean asBoolean(){
          if(status != 'active')
               false
          else
               true
     }
}
assert new Account(status:'active')
assert !new Account(status:'prospect')


You can also expand (or change) existing classes like String, Integer, etc using metaClass. Let's expand the groovy truth to return null if the string value is 'null'


     String.metaClass.asBoolean = {
                                    if(delegate  == null || delegate == '' || delegate == 'null') false
                                    else true
                                  }

     String nullString = null
     String nullLiteralString = "null"
     String validString = "JohnDoe"
     String emptyString = ''
    
     assert !nullString
     assert !nullLiteralString
     assert validString
     assert !emptyString 


Asserts are one place where the overridden logic will be applied. It works with if,while, and ternary operator as well.


//continued from previous script
println "null"?"FALSE":"TRUE"

str1 = "null"
if(str1) println "Valid String"
else println 'Null, empty or "null" literal string'


If you do not want to override the way an object evaluates to boolean globally. You can use categories.


class StringNullTruthCategory{
    boolean asBoolean(String str){
        if(str || str == 'null')  false
        else true
    }
}

use(StringNullTruthCategory){
   String parameterValue = "null"
   if(parameterValue)   {
       println 'Should not be printed'
   } else {
       println 'Should print'
   }
}

def httpRequestParmValue = "null"
print 'Valid Value: '
println httpRequestParmValue?'YES':'NO'



Similarly, you can expand Integer's truth value if value is either zero or negative value. you can expand truth value of Map based on specific key-value. You have to be careful in doing so though, completely overriding the evaluation criteria can lead to confusion. You can apply on customize builder object. Let's say you have customized builder parsing order.xml into OrderEntity who has multiple OrderItems. OrderEntity truth can be derived from all of its OrderItem.


class OrderEntity{
     ...
     OrderItem[] orderItems
     String status
     ...
     boolean asBoolean(){
          //Define based on status or status of orderItems or presense/absence of orderItems
     }
}

if(currentOrder) {
     //do time consuming process
}


You can define asBoolean objects in your Java class and use that definition to determine boolean value. However, you have to be careful of legacy Java Objects which has method asBoolean already defined for different purpose.




Blogged with the Flock Browser
Post a Comment