A blog about software development and other software related matters

Blog Archive

Showing posts with label Groovy. Show all posts
Showing posts with label Groovy. Show all posts

Tuesday, December 18, 2007

Buildr and groovyc

Buildr is a build tool that iv mentioned in previous posts, its really flexible and easy to mold custom functionality into it due to its Ruby heritage and its AntWrap utilization.
In this post im going to demonstrate how to use the groovyc ant task in order to intruduce groovy compilation into your build (which is a bit tricky).
Lets dive head first into the code:


SP=File::SEPARATOR

desc "Dummy project"
define "Dummy" do
#..
def
hashToPath(hash)hash[:group].gsub('.',SP)+SP+hash[:id]+SP+hash[:version]+SP+hash[:id]+'-'+hash[:version]+'.jar'
end

def reslove_artifacts_paths(array)
array.flatten.inject([]){|result,arti| result << repositories.local+'/'+hashToPath(artifact(arti).to_hash)}.join(File::PATH_SEPARATOR)
end

desc 'compiling'
compile.enhance([:groovyc])# this actully replaces the standart compile with the groovyc ant task

desc 'groovyc task'
task :groovyc do
classpath=reslove_artifacts_paths(RUNTIME)
ant('groovy') do |ant|
ant.taskdef :name=>'groovyc',:classname=>'org.codehaus.groovy.ant.Groovyc',:classpath=>reslove_artifacts_paths(GROOVY)
ant.groovyc(:srcdir=>path_to('src', 'main', 'java') , :destdir=>path_to('target','classes') , :classpath=>classpath){
ant.javac(:source=>"1.5" ,:target=>"1.5")
}
end
end
#..
end


The code above (if you havent guessed it until now) is the buildfile, lets disassemble it:

  • The groovyc task uses AntWrap in order to define and use the groovyc ant task, notice that we are using joint compilation which in essence suppresses the default compilation (since there wont be anything left to compile when its turn arrives) and makes our life easier (no need to mess with the ordering of the compilation steps).

  • The reslove_artifacts_paths method does what its name suggests and is required in order to make ant happy (i haven't found a nicer way of doing this) or else it wont find the required classes.

  • the GROOVY constant points to the groovy-all jar the RUNTIME points to all that is needed during compilation.



That all about there is to it.

Thursday, December 13, 2007

Compilled vs non compilled Groovy Spring beans

Spring offers great flexibility when working with dynamic languages, it enables the wiring of Groovy beans in your application with minimal effort (see), one of the coolest things about it is that it enables also the re-deployment of Groovy code with no more then a simple file override (see).

All this is fine and dandy except that it introduces quite an overhead on Spring context startup time and runtime usage, developers that use it may get the wrong impression that Groovy is Sloowww (partly true).
The fact is (as ill demonstrate next) that Spring's magic takes its toll and that there is a simple alternative to this mechanism which is to use the compiled code and not the source code in our bean definitions.

Take for example the following configurations:


Compiled:
⟨bean id="multiThreadedConversion" class="com.conversion.MultiThreadedConversion" scope="singleton"⟩
⟨property name="mapper" ref="mapper"/⟩
⟨bean⟩

⟨bean id="mapper" class="com.conversion.utils.ExtensionToAppMapper" scope="singleton"/⟩

⟨bean id="scavenger" class="com.conversion.utils.ConversionDataScavenger" scope="singleton"/⟩


Not compiled:
⟨lang:groovy id="multiThreadedConversion" script-source="classpath:com/conversion/MultiThreadedConversionNotCompiled.groovy" scope="singleton"⟩
⟨lang:property name="mapper" ref="mapper"/⟩
⟨/lang:groovy⟩

⟨lang:groovy id="scavenger" script-source="classpath:com/conversion/utils/ConversionDataScavenger.groovy" scope="singleton"/⟩

⟨lang:groovy id="mapper" script-source="classpath:com/conversion/utils/ExtensionToAppMapper.groovy" scope="singleton"/⟩

And two simple startup time benchmarks:


public void compiled() {
Date before = new Date();
ApplicationContext compiled = new ClassPathXmlApplicationContext("application.xml");
System.out.println(new Date().getTime() - before.getTime());
}

public void notCompiled() {
Date before = new Date();
ApplicationContext notCompiled = new lassPathXmlApplicationContext("not_compiled_application.xml");
System.out.println(new Date().getTime() - before.getTime());
}

Running them both resulted with the compiled version taking 0.203s to run and the the non compiled took 1.015s which is ~five times slower!

Should we conclude that the compiled version is always preferable?
Well it depends since it has its drawbacks:
  • We lose the easy deployment procedure when using the byte code.

  • G/Setter must be introduced in order to aid spring in identifying properties within classes (a serious draw back since in groovy we may use only the def keyword).
    It seems that iv got this wrong (just match the Spring id with the Groovy property name and your set).

This leads to the answer:
Use the source when easy redeployment (business logic is one good example) is required, use compiled when performance is critical.

Keep on Grooving ..

Monday, October 8, 2007

Catch the bug

Well iv just spent an hour or so on this cute little bug and thought to challenge you readers to catch it by yourself (using any debuggers IDE's etc.. isn't allowed!)
The code is in the Groovy programming language and involves two closures as follows:


def validate(assets){
def asset = assets.find() {a ->
[a.floor, a.houseNr, a.street, a.zipCode].find {val -> StringUtils.isEmpty(val)} !=null
}
asset == null ? 'all addresses are ok' : 'one address is partial'
}

This little method finds an asset within an asset list that has at least one empty address value (emptiness is asserted by org.apache.commons StringUtils).

The method makes use of two nested find methods (both accept two boolean closures) with this simple logic:
We are trying to find any asset (the wrapping find call) that has at least one empty address value (the inner find), simple enough right?

Well lets Write some tests:

def asset= new Asset()
asset.floor='1'
asset.houseNr='1'
asset.street='bla'
asset.zipCode ='1234'
assetEquals('all addresses are ok',validate([asset]))// passes
asset.floor=''
assetEquals('one address is partial',validate([asset]))// passes
asset.floor=null
assetEquals('one address is partial',validate([asset]))// bug strikes here!


Well that one last test is weird, the first initial instinct of mine was to check that isEmpty handles null as empty (ill give you a hint, it does).
Feel free to tackle it now, its not that complicated (or is it?) the following paragraph will contain the solution so stop reading now! (thats if you don't want to cheat).




The solution:
Ok lets follow along that last test:

  • The validate method input includes an asset that has a nullified floor, the first find is called.

  • The first find calls its inner find method call.

  • Now here is the tricky part, the inner find manages to scan only the first array value (floor) and returns its value (which is null!), the !=null assertion returns false to its wrapping find,now since there are no more elements in the assets list the outer find returns the faulty null.


Thats it another bug squashed!