Wednesday, July 18, 2007

About SwingBuilder

Disclamer: I will use the term "closure" quite often here and experts will say they are not closures. I still call them closure in the sense, that they are instances of groovy.lang.Closure. So If I say closure I don't mean that functional thing ;)

This time I thought I should write some things about Groovy SwingBuilder and assumptions people seem to make about it.

groovy.util.BuilderSupport

First thing you need to know is that SwingBuilder is a builder... that might be obvious, but it implies, that if I do a method call in the builder structure, then the builder will handle that call and map the method names to certain actions.

Now in Groovy we have this class BuilderSupport, that you can use to map structures in a builder. Personally I don't like that class much, because the logic looks more complicated than needed, but it fits very general cases. Anyway, the class tries to map method calls in the builder structure to calls of createNode in the builder class. There are several of them, each responsible for a certain case controlled by your method call. The most important fact here is that if your last argument is a closure, then this closure will not be part of the creatNode call, instead the closure will be used by the builder directly. I guess it is best to show examples:

def builder = new MyBuilder()
builder.start {
methodWithClosure {
methodWithMap(foo:"bar")
}
methodWithNormalArgument("I am a argument I guess")
}
methodWithClosure a normal method call with one argument, that is the closure containing the method call with methodWithMap. methodWithClosure is now mapped to createNode(Object), the object there is the method name "methodWithClosure" as String. methodWithMap is mapped to createNode(Object,Map), where the first is again the method name and the map is our [foo:"bar"]. If you combine one normal argument and a map entries, then you get createNode(Object,Map,Object), where the last one contains your normal argument. And if there is no map and no closure, just a normal parameter, like with methodWithNormalArgument, then createNode(Object,Object) will be called. This logic supports only 1(!) normal argument, but that is enough in general.

After the createNode call of your choice is made the return value of that will be hold, I will call this currentNode. To connect the currentNode and its parent, which is done by setParent(currentNode,parentNode). now what is parentNode? Remember? we still have a closure to call. When we do, then our currentNode becomes parentNode and the new currentNode will have a parent. So the first time setParent is called we are not in a closure that belongs to the builder, which means the parentNode is null. If you would build a tree using this logic, then you would build the tree starting with the root and then adding node by node in I think it is called preorder traversal.

Architecture of SwingBuilder

SwingBuilder is making use of these methods in BuilderSupport. For each method call SwingBuilder creates a new instance of a bean we specified with the method call. So
frame(title:"I am a JFrame")
will create a new JFrame instance and set the property title. And as we just learned
frame(title:"I am a JFrame"){
label(text:"I am a JLabel")
}
will also create the JFrame, the property title will be set again, then the closure will be executed causing the label method to create a JLabel and the text property on that label is set. After that setParent is called with the first parameter being the JLabel and the second parameter being the JFrame.

The logic we stored in setParent will connect our frame with the label by frame.getContentPane().add(label). SwingBuilder#setParent knows several cases and handles adding a JMenuBar to a JFrame different from adding a JLable. This method and helper are around 100 lines, about 20% of SwingBuilder source.

So basically SwingBuilder is a builder that maps method calls to bean creation actions, using map arguments to init the beans and the closures to connect the created beans. It using a mapping method name -> bean class and contains itself nearly no methods you call when using SwingBuilder.

Names supported by SwingBuilder

If you are not sure if SwingBuilder supports a swing widget, just remove the J, keep the next letter in lower case and try it. For example JEditorPane becomes editorPane, JSplitPane becomes splitPane (both supported). But SwingBuilder does not only know widgets, it does also know layouts. there is usually no 'J', so just use the next letter in lower case, as in gridBagLayout, flowLayout or others. You can use the layout as normal method causing the layout property of the container to be set. I have often seen code like:
frame(layout:new FlowLayout()) {
label(text:"1")
label(text:"2")
}
but you can write that also as
frame() {
flowLayout()
label(text:"1")
label(text:"2")
}
I like this version much better, because you do not need to import FlowLayout and can give the layout some options while keeping the frame call simple. Groovy supports all the normal layouts, even Box layout. Another special thing is maybe the method gbc, which is the same as the method gridBagCosntraints, which maps to GridBagConstraints. Maybe I should also mention TableLayout, which tries to implement the layout you know from the table tag in html. It needs tr and td calls to place the componentes... really just like in html. Take a look at alpahbetic widget list to get an ideas what you can do.

Another important link is extending SwingBuilder. It does not mention the possibility of simply subclassing the class SwingBuilder, but that should be obvious and was done for example by SwingXBuilder.

All in all it is a bit difficult to provide a documentation for SwingBuilder, because you still need to learn swing, SwingBuilder doesn't help you with that. And then it is just connecting instances of classes... For example when people ask how to attach an action to a JButton and I tell them to assign a closurey to the actionPerformed property, then I am not talking about a special property, actionPerformed is defined by the bean specification and assigning a closure to that property is a normal thing in Groovy.

New things in 1.1-beta2

We got complains that if I do
def frame = swing.frame(...) {
...
}
frame.pack()
frame.visible = true
that the resulting gui will not be constructed in the EDT thread, but in the normal main thread. Now I am no Swing expert and I always assumed it makes no difference, but it seems that future changes in Java will need you to change in the EDT. And of course it is more clean that way too. So we eneded with adding two methods, the first is edt, which causes the attached closure to be executed while in EDT. the code looks then like
swing.edt {
def frame = frame(...) {
...
}
frame.pack()
frame.visible = true
}
unlike many other methods available in SwingBuilder the edt method is a real method and no registered widget. the other method is static and called build. It will automatically create a new SwingBuilder instance and call the attached closure with that instance as parameter
SwingBuilder.build {
def frame = frame(...) {
...
}
frame.pack()
frame.visible = true
}
build uses the edt method, so we build the GUI while in the EDT thread, just like before.

Future Plans

I think SwingBuilder is already a nice piece of work, but its evolution might not stop here. Currently I am thinking about integrating a Binding framework. That would some update logic to SwingBuilder, something you have to do all by yourself atm. For example imagine a label and a button and each time you press the button the label text should show a higher number. What do you do? You use a closure as actionPerformed for your button that increases a number and sets a new text for the label...
import groovy.swing.*
import groovy.swing.impl.*;
import javax.swing.border.EmptyBorder
import javax.swing.WindowConstants

def numClicks = 0
def state = {"Number of button clicks: $numClicks"}
def label
SwingBuilder.build {
def frame = frame (
title: "SwingBuilder Label Update",
defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE
){
panel (border: new EmptyBorder(30, 30, 30, 30)) {
gridLayout(rows: 2, columns: 1, vgap: 10)
button (text: "I'm a button!",
mnemonic: "I",
actionPerformed: {numClicks ++; label.text = state()})
label = label (text: state())
}
}
frame.pack()
frame.visible = true
}
note the closure state, that is called at different places? that's quite ugly I think. With a binding framework the code might become
import groovy.swing.*
import groovy.swing.impl.*;
import javax.swing.border.EmptyBorder
import javax.swing.WindowConstants

def model = new BindModel(numClicks:0)

SwingBuilder.build {
def frame = frame (
title: "Binding and SwingBuilder Test",
defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE
){
panel (border: new EmptyBorder(30, 30, 30, 30)) {
gridLayout(rows: 2, columns: 1, vgap: 10)
button (text: "I'm a button!",
mnemonic: "I",
actionPerformed: {model.numClicks ++})
label (text: bind("Number of button clicks: $model.numClicks"))
}
}
frame.pack()
frame.visible = true
}
as you see the need to keep an external closure vanished along with the need to keep a reference to the label. the way it will be used in the end is not yet sure, this is just a sketch based on a simple implementation I made.

While doing my "research" in this area I noticed that binding frameworks are not that well known. At last by the people I know. I myself didn't here about that before, but I am usually not doing much with swing. So I got a bit puzzled why people don't know these things if they can save so much code... but then I saw it. Some of these frameworks are producing rather cryptic code, that makes sense for the framework but is just plain hard to read. Your former models are now hidden in abstract constructs, but you still need to connect the things. So I guess SwingBuilder could find a more "natural" way by hiding all these things.

We will see.

Wednesday, July 04, 2007

Joint Compilation in Groovy

Note: This is not implemented since today, it is already some weeks old, but there was no information about it on the net... So I wrote this

When working with Languages like Groovy you naturally mix Groovy and Java all the time. But the problem then arises to compile the resulting monster. Especially the Eclipse plugin for Groovy makes you sometimes think your project will compile outside as nice as inside Eclipse. But it might not. Consider for example this case

class A {
B b;
}
class B extends A {}
And think A is written in Groovy, but B is written in Java, or the other way, A is written in Java, but B is written in Groovy. It is clear, that when you compile B, you need class A as well, because the class might be final or abstract or other things that need to be checked. But when you compile A, you will see that it refers B, which means you need to compile B as well. Now if this is one compiler we have no problem, but A and B are written in different languages with compilers not sharing their class information. That means we are stuck. And while this example looks a bit artificial, you get very fast into this situation in a larger project. Who would keep track of not referencing Groovy classes from the Java side to get the compilation done? It's disturbing.

Solutions?

Now the one solution would be to let the compiler share their class data. The Groovy compiler is able to do that, the eclipse compiler is able to do that, we might see a bright future for this in the future. But for example JavaC is not able to do this. At last I don't know how.

Another way is to create stubs for the Groovy classes, run the Java compiler with these stubs, then run the Groovy compiler and overwrite the generated stubs. Alex Tkachman was so free to show us Groovy people how to do this and provided a patch, we could us as base to get this version of the compilation running.

How it Works:

The details of the stub generation are not so important I think, they are created as Java files from the parse tree the Groovy compiler provides in a temporary directory and then feed to JavaC along with the normal Java files. You don't need to start the compiler yourself, the Groovy compiler will do this for you right after the parse phase and then continue with its normal compilation process.

Controlling JavaC:

Since we now have a combined compiler we of course want to use it in our build, but the problem is that javac would by default created a wrong bytecode version for us, we need 1.4 compatible bytecode, so source and target options are needed at last. I then decided to forward the options to the compiler from the command line of Groovy. So if you do
groovyc *.groovy *.java -j -Jsource=1.4 -Jtarget=1.4
You will get the java files compiled for 1.4. -j turns the joint compilation on , the -J parts are gving key-value pairs to the compiler. Using Options without value is also possible using the -F option, just without the equals part like -Fdeprecation. Anything the JavaC compiler supports can be dropped in there... Of course some special options like the VM memory size would not make sense since the VM is already created.

For the GroovyC Ant task the picture is a bit different. first I thought about a way to generically define attributes for the GroovyC task I can forward to JavaC... But me not being the Ant expert I gave this up and decided to do the following work around
<echo message="Groovyc of test code."/>
<java classname="org.codehaus.groovy.ant.Groovyc" fork="true" maxmemory="128M">
<classpath>
<pathelement path="${mainClassesDirectory}"/>
<pathelement path="${testClassesDirectory}"/>
<path refid="testPath"/>
</classpath>
<arg value="${testClassesDirectory}"/>
<arg value="${testSourceDirectory}"/>
<arg value="-j"/>
<arg value="-Jsource=1.4"/>
<arg value="-Jtarget=1.4"/>
</java>
Oh, that reminds me that the GroovyC task needs a fork ability. Anyway, that's when using the ant task from the command line. If you want to use it normally, then
<groovyc
srcdir="${mainSourceDirectory}" destdir="${mainClassesDirectory}"
classpathref="groovyMainCompileDependencies"
jointCompilationOptions="-j -Jsource=1.4 -Jtarget=1.4"
/>
can be used. Same game as on the command line.

What this solution can't do:

Yes, there is a downside. Ok, I think it is already a downside that we have to use a temporary directory, but another one is that we need to know all files we want to compiler before compilation. I don't think that is a problem when running a ant or maven based built, but for the typical usage on the command line, where you just compile your main class and the compiler will get a hold on all further classes will not work. To be more specific, it will not work when the Groovy compiler needs to get an additional Groovy class and the Java compiler would need that class too. That's because in this case no stub will be created and thus the java compiler will fail telling you it can't find a that class. On the other hand GroovyC works with the resulting class files, so if a Groovy class refers a Java class and JavaC did not compile it, then GroovyC won't be able to compile it either... well, ok, just give the compiler all needed files ;)

Future Work:

The current implementation uses JavaC directly a nice framework would be nice here to have more than just this compiler. And there is for example JCI, but JCI seems not to support options... well we need to take another look at it, maybe it supports enough. On the other hand I am thinking about integrating the JavaC task from ant. in that case we could maybe use the normal task as nested element (with some tweaks) and have all the abstraction to different compilers ant allows. Of course by directly using the Eclipse compiler (it is usable outside the IDE) we could let the compiler share class data and then compile files that are not part of the file list given at runtime.

But I think the ant task version will make it. the work around with the "-j -J -F" options might then vanish.


But none the less, have fun with the upcoming
Groovy 1.1 beta 2

Tuesday, March 27, 2007

Visitor Pattern in Groovy

Shame on me, such a long time without update. I was too busy it seems. I just wrote a small article about how to use the visitor pattern in Groovy. Enjoy the Visitor Pattern in Groovy and ignore the misspellings ;)

If you think I should mention other patterns as well, tell me please.

Saturday, January 06, 2007

AST macros and mixins

Hi all,

I know my last article was written some time ago, but I was busy with Groovy 1.0 bug times. Anyway. This is another part of my "beyond Groovy 1.0" series, only that we are now officially in that era and I think I no longer need to prefix the title with that.

So my next wild idea is about a macro mechanism for Groovy. But not the kind of macros you know from C or such, no I think of macros rewriting parts of the AST used by our compiler. So the idea is not really something new, it is something the compiler does already provide. The new thing is to let the compiler do the integration steps for you automatically. No need to add a PhaseOperation to the compiler or such.

No, I have not really thought of a syntax yet, let us think about this as a case study and not as a final draft or something. Ok, back to title. let us say, there is a statement like the import statement and let us call it macro. So when we want to use a macro we simply tell the compiler this by:

import macro Foo

or by
import macro Foo as bar

and let us assume the compiler can use them like a method:
bar {
// a block containing code
}

looks much like the dynamic features we already provide, but in fact the compiler recognizes "bar" as macro and does not produces a method call with a closure instance for this, no, instead the compiler takes the logic provided by our Foo class and applies it to this part of the code.

Why should we do that? One thing I always disliked in Groovy is the huge amount of keywords. Do they really have to be keywords? One example for this is synchronized. Usually you do something like:
synchronized (object) {
// code using object
}

But isn't that almost our macro "bar" from before? It is, not only almost. In fact it is really alike, the compiler would transform that into
synchronized (object, {  ...t })

just like the bar example
bar ({...})

it is no different. So that would mean we could remove the keywords "for", "while", "assert" and "synchronized". Ok, not much... but still it is a step forward. That would still mean that the do-while loop is not supported, but maybe there is a solution for this too.

How would Foo possibly look? Well I guess something like:
class Foo {
static phase = Phases.CONVERSION
def visit(ASTNode[] contextPath, SourceUnit source) {
// ... transformation code here
}
}

The compiler would take a look at the Foo class ensure that there is a default constructor and a static field named phase. Then the compiler would create a new instance of the class and add it to the phase operations it already provides, plus a filter to ensure only the correct classes are affected by this. So if the compiler compiles the file it goes along the AST until it finds the macro and then does execute it.

That's pretty easy to implement, really no big deal, but the impact might be big. I think such a construct would be the first step to unify the Groovy grammar parts and to remove special constructs. Well, the thing really needed for this is a way to exchange/remove statements in the AST. That is currently not possible. It is only possible to transform expressions, but not statements. But well, that is no problem we can't solve, is it?

The mentioned keywords earlier could be seen as macros themself. That doesn't mean that we can remove these statements from the AST, but it would mean a programmer could define additional keywords as he likes. For example a macro transforming a closure into a SQL statement. We already have this, but wouldn't it be exciting to have that at compile time? I mean with different checks and without runtime impact. the macro could use any expression, for example
  sql {
select row1,row2
from tx
where id==26
}

I am also thinking about SODA queries or queries for GORM. The above can't be interpreted using a normal closure, because I used 3 statements that are interpreted as method calls. There is for one select(row1,row2), then from(tx) and where(id==26). So to correctly interpret this we have to use the getClassNode method in MetaClass, but that relies on runtime analyzes of the source file atm. Yes, we are going to change that, but it means to store the source inside the closure in compressed form or else we wouldn't be able to ensure the correct interpretation. With these AST makros we are able to compile that directly into the goal construction. I mean even different SQL dialects could be covered by this.

But SQL is just a example. I used it only to illustrate the abilities a little. I know that this article does only give a little idea about how it might work and writing this doesn't mean it will go into any version of Groovy. But I think the idea is quite simple and yet powerful.

But this is not all... AST handling is complicated and not really something that would make your day. so I think about going a step further, in fact I am planining to adding this pretty soon. I am talking about AST level mixins.

"Ok, what's that again?" you may ask. I think of defining a chunk of code as normal groovy script and a defined way ofr a phase operation to use that code to modify the AST. This chunk of code does itself not contain any AST handling code, it will just be used as archetype for the compiler to produce the real code. This might be a simple thing as
class X {
long id
}

causing the compiler to add a field named id to the currently processed classNode, or something more complex. Well we have a problem when it comes down to bytecode instruction. For example if we want to replace a for loop we would have to define jumps. So, as long as there is no mechanism to represent this, there is no way this transformation by example will work for all kinds of macros too. But well, this is like doing research. At the beginning you have only a vague idea of how things might work. you do experiments to see if your expectations are correct and you develop new ideas if they do not or if the experiments are uncovering no facts.

But still, the idea is exciting somehow. I am sure another language does already have a construct like that... well I am thinking about LISP here. I wouldn't dare to compare this to the macros in LISP (I am talking about Common LISP), but possibly they will become alike in the future after doing same practical work. LISP does have a more easy part here, because LISP does have a much simpler syntax than Groovy. Doing structural work in such a language is naturally more enjoyable than in a complex language like Groovy. But I still think it can be done.

Btw, this is no replacement for DSLs looking like natural language, but that is more a syntax issue, than an issue of AST macros.

Wednesday, January 03, 2007

Groovy 1.0 is here!

16 hours ago Groovy 1.0 was released. The work of 3,5 years. So many discussions, so many code was produced, removed and reworked.

In my eyes this is not the final version of Groovy, nor is it perfect. But it is important to give a stable version to the world out there. I hope many people will like that Groovy. But that doesn't mean Groovy wouldn't evolve anymore. There are many ideas we can try out now since we do not any longer have to focus on the release. In the release notes you will find not much this time, we fixed a number of bugs, but these are more like minor adjustments. But Groovy In Action and GroovyGrail.com do show increasing interest.

The next months will be spent to improve the documentation and to really start the JSR process. Then Groovy will be really like a standard and get a good documentation.

New Layout




Since the changes on blogger.com my blog wasn't working properly, so I decided it is time to get a new layout. Making custom layouts here is not the most nice thing to do, because I always have problems with layout support pictures. But putting them in a post and reusing the link to the image allows me to have layout pictures as the two on top, that are nearly invisible. The layout is not perfect and my javascript for keywords is no longer working, but I think it is a good start. A multicolumn layout made in css can really be difficult to do. This page currently consists of about 4 columns, 2 for images, 1 for the sidebar and 1 for the content itself.

Wednesday, November 08, 2006

ChitChat with the Groovy Compiler

Ever wished to be able to influence the compiling process in Java?

To do this you usually don't influence the compiler directly, you use AOP tools with strange syntax rules and extra files for configuration or you are working on the bytecode level and sue the instrumentation API. But these technics have their limits. To be able to instrument a class you need a ready compiled, the verifier passing class. What if you can't produce such a class?

But ok, let us go some steps back. Programming by convention is in all mouths, so let us look at adding a method depending on the class name. I guess people would use a inter-type declaration in AspectJ to add methods to a certain class. The problem here is, we don't know the class before. We react to the name of the class and only if the name fits, we add the method.

Another thing is adding imports. There is no point in adding imports in a class file, all class names in a class file are already resolved against the imports. Adding another import would be pointless. But if you want to let people write a small peace of code where they can forget about importing every class they use, then we are talking about adding something to what the compiler gets as input. The most easy solution would be to use some kind of macro system. Expand the macros and give the result in the compiler. But then, what is about the line numbering? Exceptions will show useless information about the position in the source file, compiler errors will point to invalid places. That's a bit bad.

Compiler are normally working on an AST, an abstract syntax tree. Such a tree represents the source as a tree, each node is a part logic created by the source. For example, the expression "foo.bar()" is in Groovy a method call expression with foo as the object the call is made on, bar the name of the method and an empty number of arguments. Such a method call expression is a node in the AST. I am afraid that explaining all the expression types and statements in Groovy would be too much for this small article. I suggest to look into the packages org.codehaus.groovy.ast.expr, org.codehaus.groovy.ast.stmt and org.codehaus.groovy.ast. Of course having around 35 expressions and 19 statements doesn't make this task very nice, but it is needed. Groovy uses the visitor pattern to visit the classes. That makes it a bit problematic for people how are not used to that. but it really is nice to have that.

Each phase of the compilation process after the AST is created consists of a visitor travaling along the AST replacing or modifying nodes. Btw, the Groovy AST is for example used in Eclipse for the outline.

Now imagine you could change the AST by yourself. Rename methods, add code, add methods... yes, right, we wanted to add a method if the class name fullfills a certain convention.

Now the Groovy compiler offers here some hooks you can use to change what the compiler will produce. What I will explain now counts only for the case that a file is compiled using the GroovyClassLoader, for example because a script is found in the classpath or because we use the GroovyShell to execute a script. The basic process to creat a compilation unit, that will hold the AST and other information, add a source to the compilation unit and then start the compilation. By subclassing GroovyClassLoader you can overwrite createCompilationUnit(CompilerConfiguration, CodeSource), the very first step. The CompilationUnit is really our compiler. It holds all the logic. So if you return a subclass of CompilationUnit here, you would return a custom compiler. But I don't want to go this far here.

I talked about hooks, but subclassing CompilationUnit would be a bit big possibly. I talked also about the phases a compiler goes through and that's where CompilationUnit offers hooks. The addPhaseOperation methods do allow you to give the compiler additional logic for a phase of your choice. In Groovy these phses are:

  • initialization: open files setting up the environment and such
  • parsing: use the grammar to produce tree of tokens repersenting the source
  • conversion: make a real AST out of these token trees
  • semantic analysis: check for all things the grammar can't check for, resolv classes and other things
  • canonicalization: complete the AST
  • instruction selection: choose isntruction set, for example java5 or pre java5
  • class generation: create the binaries in memory
  • output: write the binaries to the file system
  • finalization: cleanup
not all these phases are really filled, the canonicalization step is currently empty, but that is a implementation detail. If we want to operate on the the AST then we need one, thus the conversion phase is the most early phase to do that. You have to decide if your operation is about changing a certain source file or a certain class. Each file may contain multiple classes, so this is not equal. For example if we want to add an method, then it makes not much sense to work on the source (SourceUnit) but on the ClassNodes instead.

In our example we would call the addPhaseOperation(PrimaryClassNodeOperation, int) method. You may wonder about the name primary class node operation. A class node represents a class, but in the compilation process there are two kinds of classes: precompiled classes and classes we want to compile. These primary class node are classes we want to compile.

If you know the AST then the next steps are quite easy. For example:

class MyOperation extends PrimaryClassNodeOperation {
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
classNode.addMethod("foo", OpCodes.PUBLIC, null, null, null,code);
}
}

This would add a method named foo to every class we compile, foo takes no arguments, is public and has the return type Object. The contents of the method are stored in "code". I haven't specified that here to keep the article not totally complicated. Ok, again let us think back to the orignal task of adding a method if the class name fullfills a certain convention. For example if a class is XyzFoo, then add a method xyz, if the class is AbcFoo, then abc. Ok, that is a bit crazy, but well, just for the demonstration of the flexibility:

import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.classgen.GeneratorContext;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.Phases;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation;
import org.objectweb.asm.Opcodes;

import groovy.lang.GroovyClassLoader;

class MyGroovy extends GroovyClassLoader {
protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
CompilationUnit cu = super.createCompilationUnit(config, source);
cu.addPhaseOperation(new PrimaryClassNodeOperation() {
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
String name = classNode.getName();
if (name.endsWith("Foo") && name.length()>3) {
name = name.substring(0,name.length()-3);
BlockStatement code = new BlockStatement();
classNode.addMethod(name,Opcodes.ACC_PUBLIC,null,null,null,code);
}
}
},Phases.CONVERSION);
return cu;
}
}

Grails does use this mecahnism to add the toString and hashcode methods as well as the id field in domain classes.

Another easy example is adding a import. But since we don't add an import to a specific class, but to all classes in a file, we are operation on the SourceUnit (representation of the source file) so we use a SourceUnitOperation.

cu.addPhaseOperation(new SourceUnitOperation() {
public void call(SourceUnit source) throws CompilationFailedException {
source.getAST().addImport("User",ClassHelper.make("my.company.UserDAO"));
}
},Phases.CONVERSION);

here we add an import for UserDAO and make the class known as User inside the file we compile. That is comparable to "import my.company.UserDAO as User" in Groovy.

As you may see this is much more than aspect oriented programming could do. You can place arbitary logic inside the compiler and modify the ASTs. If you want to do more complex operations or more local ones, then you might have to really go into the AST. I suggest to use the LabelVerifier as entry point for this. A little debugging helps you to understand how the AST looks like and how the visting works. I plan to write a big documentation about these things, but this will be on the Groovy wiki then. The purpose of this article is just to give you a insight in the internals of the compilation and how it can be influenced from the outside. Without knowing the AST there is not really much you can do. It is not that the AST is very complicated or bad documented, but learning about over 60 classes isn't done in a short form. The biggest exmaple of AST traversion is AsmClassGenerator, the part in the compiler creating the binaries. But it is a big class, not too good to learn.

My plans for the future are to add an mechansim that allows to write some text that gets mixed into the classes the compiler produces. In the import example above you would maybe write something like
cu.mixinPerSource("import my.company.UserDAO as User")
. Or in the method example:
cu.mixinPerClass {"def ${it[0..-3]}(){}"}
. But it looks like this will ahve to wait for post 1.0

You could also use the AST to transform any DSL containing binary operations such as "&" and "<" into a builder or a method based version. You could transform it into a database request or whatever. There are many possible usages of this. And in fact something like that is already used in GroovySQL - but well hidden ;)

So might I ask again: Ever wished to be able to influence the compiling process in Java?