Sunday, January 31, 2010

Exploring google collections - Part 1

Google Collection 1.0 released
Google collections finally hit version 1.0. API provides rich data structures building on JDKs collection API. It also provides utility classes for working with collections. With this post I want to focus on few google collections classes and demonstrate how they help in working with collections. In part 1 of the post, we will deal with very simple example. Later in part 2 of the post, we will work with more involved real life example.

We will focus on these classes:
Scenarios
While working with collections you may have noticed that code gets cluttered with for loops, nested for loops, or with for loops with embedded if loops. In most of these scenario what you are trying to do is to iterate through a given collection, either to search for specific elements or to operate on specific elements.

Lets break down the typical cases:
1. Iterating through a given collection and finding a specific element(s) based on criteria

for(Element element: elementsCollection){
     if(element.equals(something){ //Or any other test criteria based on state of element object
          //either add to collection of elements
          //or return this element
     }
}
2. Iterating though a given collection and if certain criteria matches perform operation on the collection

for(Element element: elementCollection){
     if(element.equals(something){
          //or operate on this element
     }
}
As an outcome of this, code ends up with
  • Code duplication of your iteration logic
  • Code duplication of your condition (matching criteria)
  • Code duplication of operation on the specific elements (This however can be avoided, if operation is re-factored into a method)
Google Collections Approach
Lets start with very simple example, here is how google collection can help:
1. Define you matching criteria using Predicate like

            Predicate<String> validEmailAddress = new Predicate<String>(){
                public boolean apply(String emailAddress){
                    return emailAddress.contains("@");
                }
            };
This can be used as

List<String> emailList = Lists.newArrayList("abc@gmail.com", "xyz@gmail.com", "aaagmail.com");
Collection<String> validEmailList = Collections2.filter(emailList, validEmailAddress);

2. Define your operation on element using Function like

        Function<String, String> extractUserName = new Function<String, String>(){
            public String apply(String emailAddress)
            {
                String userName = emailAddress.substring(0, emailAddress.indexOf('@'));
                return userName;
            }
        };
This can be used as

        List<String> emailList = Lists.newArrayList("abc@gmail.com", "xyz@gmail.com", "aaa@gmail.com");
        List<String> userNameList = Lists.transform(emailList,extractUserName);

We will take on more complex DOM-like tree based data structure in part 2 of the post...

Blogged with the Flock Browser

Saturday, January 23, 2010

Helpful tips - Working with AST Transformation

I have been playing with Groovy AST transformation for some time now. You can walk through some of the earlier posts here. With this entry I want to capture some of the lessons learnt, tips, etc.
 
Using AstViewer Tool (Inspect Ast)
With Groovy 1.6 AST transformation, one of the difficulty was to come up with tree structure for the code you want to inject or change. It involves calling complex set of Statement and Expression APIs. It is ridden with intricate details of language grammar. With groovy 1.7 AstBuilder, you can use buildFromString and buildFromCode which is lot more easier. But still if you have to use buildFromSpec you will need to have some understanding of Statement/Expression API.
 
One of the tool I have found useful is Groovy Console's AST Browser or Eclipse's ASTViewer. Write code you want to generate language structure for and try to replicate using API or using AstBuilder's buildFromSpec. The tool has gotten better from 1.6 to 1.7.
Open Groovy Console and type in following code

            def advice = new String("Hello AST")
            println advice

Go to Script --> Inspect Ast (or press Ctrl+T) and you will see the AST structure needed.

 
Educated Guess in Script
With AstBuilder now you can just start building AST in main method or just as script. This has proven to be useful if you just want to compare what you are generating with what is displayed in AstBuilder.

def nodes = new AstBuilder().buildFromXXX{
}
 
Working with Variables
If you are using variables that gets replaced during runtime you may face problem generating AST. One of the method that I found useful was to replace the variable with static value and see if it works. If it does than the problem is possibly due to the type of the variable.
For example, I wanted to generate

          def advice = new <<variableClassName>>()

where variableClassName will be passed in from annotation value. One option is to try generating it with static value like java.lang.String (or just String), if it works than there is some problem with the type of the variable you are passing.
 
Compile file individually (if using IDE)
Sometimes the tools you are working with just does not seem to give different output even when you are changing things around in your code. Sometimes stale classes just gets called and you never see the output from the updated classes. You may want to compile both transformation class and the class where the transformation gets used. 
 
ByteCode Viewer
Also using Byte Code Viewer like this helps in looking at the classes that are getting generated. You can also write your class how it will look after AST transformation. Use byte code viewer to see the class and compare it with the class that is being generated through AST Transformation. See which statements are properly generated and which are not.
 
Testcases
Another extremely resourceful source for AstBuilder is test cases found here. It contains rich example set of how to use each node in the builder specifically for buildFromSpec option. AstAssert is another excellent utility to compare and test expected and actually generated structure. Looks like AstAssert class is not packaged with groovy-1.7, so you may need to download and drop it in your project.

Divide and Conquer
Treat each section of code for which AST is being generated as separate section. Comment out blocks of code and gradually uncomment them to see which section is actually failing and/or not giving desired output.
 
Hope this helps! Drop in a line to share your tips or problems you face with Groovy's Ast transformation. 

Blogged with the Flock Browser

Monday, January 18, 2010

Revisiting Groovy AST Transformation with AstBuilder

Groovy AST is powerful tool to inject changes into classes at various compile phases. It allows one to operate on AST (Abstract Syntax Tree) to manipulate class structure.

With Groovy 1.7 AstBuilder there are easier ways to write AST transformation. One can build AST nodes using one of following three options
  • Build From String
  • Build From Spec
  • Build from Code
Previously on this blog, we experimented with Groovy 1.6 AST Transformation Example and also AOP style usage  at Groovy AST Transformation - AOP Style. Lets revisit this transformation from earlier post.

Lets see how we can generate the AST tree using these new methods from AstBuilder. Recap this previous post before proceeding ahead.

Looks like we need to rewrite initAdviceCall and createMethodCall to experiment with new methods of AstBuilder.

Build From String
Using buildFromString the task would become very easy. With this options, it is not required to build complicated statement and expression structure. All you need to do is embed code within string and pass it in to buildFromString method. If code you generate is not completely static in nature, you may have to parameterize the value. Here in this example, the declaration of "advice" instantiation depends on the Class value defined in the annotation.  

  def initAdviceCall(classNodeType) {
    def codeString = "def advice = new " + classNodeType.type.typeClass.canonicalName + "()"
    def buildNodes = new AstBuilder().buildFromString(CompilePhase.SEMANTIC_ANALYSIS, true, codeString)
    Statement stmt = buildNodes[0].statements[0]
    stmt
  }

  def createMethodCall(method, Parameter[] parameters) {
    def codeString = "advice.before (" + "'$method.name'" +", [" + parameters.collect {it.name}.join(',') + "])"
    def buildNodes = new AstBuilder().buildFromString(CompilePhase.SEMANTIC_ANALYSIS, true, codeString)
    Statement stmt = buildNodes[0].statements[0]
    stmt
  }

Build From Spec
buildFromSpec option is more verbose. It also requires you to understand internal structure that is required to be build. With use of GroovyConsole's Inspect Ast option, it is not difficult to come up with the AST structure.

  def initAdviceCall (classNodeType) {
    def buildNodes = new AstBuilder().buildFromSpec {
      expression {
        declaration {
          variable "advice"
          token "="
          constructorCall(classNodeType.getType().getTypeClass()){
            argumentList()
          }
        }
      }
    }
    Statement stmt = buildNodes[0]
    stmt
  }

  def createMethodCall(method, Parameter[] parameters) {
    def buildNodes = new AstBuilder().buildFromSpec {
      expression {
        methodCall {
          variable "advice"
          constant "before"
          argumentList {
            constant method.name
            list {
              parameters.each {variable it.name}
            }
          }
        }
      }
    }
    Statement stmt = buildNodes[0]
    stmt
  }

There are some differences between using API directly and using spec builder option. One thing specifically that threw me off was that ConstructorCallExpression takes in ClassNode as parameter, however the constructorCall in builder takes Class. It wouldn't have been much of an annoyance, if I had read GEP-2 which states that any expression taking ClassNode, for builder you just need to pass class instance. Well in this example, value provided by annotation was ClassNode, so I had to get Class and pass it on to constructorCall.

Build From Code
Unlike above two options buildFromCode option did not work for me in above scenario. The problem I faced was I couldn't do def advice = <VariableClassName>() without using reflection. Method would have looked something like this

def initAdviceCall(classNodeType){
new AstBuilder().buildFromCode {
     def advice = classNodeType.getType().getTypeClass().newInstance()
}
Similarly, for createMethodCall, I would have to use reflection for passing in parameters.

More later...
Blogged with the Flock Browser

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