Software Development

WYSIWTF

Too funny

AJAX/Web 2.0
Design
General
Quotes
Software Development
Thought

Comments (0)

Permalink

Implementing DSLs in Groovy (OSCON slides online)

I have put the slides and some code from my OSCON 2007 talk online.

Had a lot of fun giving the talk. There is a lot of interest in Groovy out there! Thanks to everyone who came to the talk for the wonderful questions!

General
Grails
Groovy
Java
OJUG
Self
Software Development
Speaking

Comments (0)

Permalink

Groovy + Annotations + Aspects

I have been doing a lot of digging into Groovy and DSLs lately, getting ready for my OSCON talk next week.

The Groovy language has great built-in support for creating DSLs. Along with its dynamic nature, Groovy has the “use” keyword for working with categories, and coming in 1.1, the ExpandoMetaClass if you want to complete.

“Use”ing Categories

Categories help you do scoped “extension” to normal every day objects. An example is in order:

  1. class TacoCategory {
  2.         static String getTacos(final Integer i) {
  3.                 “${i} tasty tacos”
  4.         }
  5. }
  6.  
  7. use (TacoCategory.class) {
  8.         println 2.tacos     // outputs -> "2 tasty tacos"
  9. }

So, inside the use block, there is now (effectively) a new property on the Integer class, called tacos, that will return a string describing your delectable entree. This is a very powerful technique, and is very useful for developing your own expressive syntax.

One drawback to this technique is that you have to define where you are using it. Use can be extended into closures, but does not always extend into predefined methods.

  1. aClosure = { println 3.tacos }
  2.  
  3. use (TacoCategory.class) {
  4.  aClosure.call()  // outputs -> "3 tasty tacos"
  5. }
  6.  
  7. aClosure.call()  // Exception No such property: tacos for class: java.lang.Integer
  8.  
  9. // However, you can do this from Java (or Groovy):
  10. GroovyCategorySupport.use(TacoCategory.class, aClosure)  // outputs -> "3 tasty tacos"
  11.  
  12.  
  13. //  calling methods on a class:
  14. class A {
  15.         public String getTacos() {
  16.                 4.tacos  // has not been evaluated yet
  17.         }
  18. }
  19.  
  20. println new A().getTacos()   // Exception No such property: tacos for class: java.lang.Integer
  21.  
  22. // but you can do this:
  23. use(TacoCategory.class) {
  24.   println new A().getTacos() // outputs -> "4 tasty tacos"
  25. }

Groovy + Annotations + Aspects = annotated “use” clause

I was talking about Groovy Categories with Blaine Buxton, and was telling him that I did not like having the “use” block inside my DSL code, and wanted a more transparent approach. He suggested that perhaps an Annotation and an Aspect would do what I was looking for.

With the 1.1-Beta1 Release, Groovy has built in support for Java Annotations, and since Groovy compiles down to byte code, there is implicit support for Aspects. Putting these two things together allows us to create an annotation for a more powerful use:

  1. class AnnotatedObject {
  2.  
  3.   @Uses(category=[MeasurementCategory.class])
  4.   public String fourPoundsOfSomething(something) {
  5.     (4.lbs.of(something)).toString()   
  6.   }
  7. }

With a simple annotation, @Uses(category=[list of category classes]), we now can define them for any method we want, without having to put them into the method body.

Here is the Annotation code:

  1. package com.nimblelogic.groovy.dsl;
  2.  
  3. import java.lang.annotation.Inherited;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6.  
  7. @Inherited
  8. @Retention(RetentionPolicy.RUNTIME)
  9. public @interface Uses {
  10.   public Class[] category();
  11. }

And here is the Aspect code:

  1. package com.nimblelogic.groovy.dsl;
  2.  
  3. import groovy.lang.Closure;
  4.  
  5. import java.util.ArrayList;
  6. import java.util.List;
  7.  
  8. import org.aspectj.lang.JoinPoint;
  9. import org.aspectj.lang.annotation.SuppressAjWarnings;
  10. import org.aspectj.lang.reflect.MethodSignature;
  11. import org.codehaus.groovy.runtime.GroovyCategorySupport;
  12.  
  13. public aspect UsesAspect {
  14.        
  15.      pointcut allMethods(): call(@Uses * *(..));
  16.    
  17.     @SuppressAjWarnings
  18.     Object around(): allMethods() {
  19.         List< class >  classes = getCategories(thisJoinPoint);
  20.  
  21.         Object result = null;
  22.         if ( classes.isEmpty() ) {
  23.             result = proceed();
  24.         } else {
  25.                 result =
  26.                         GroovyCategorySupport.use(classes,
  27.                             new Closure(thisJoinPoint.getTarget()) {
  28.                                 @Override
  29.                                 public Object call() {
  30.                                     return proceed();
  31.                                 }                         
  32.                             });
  33.         }      
  34.        
  35.         return result;
  36.         }
  37.    
  38.     @SuppressWarnings(“unchecked”)
  39.         private List< class > getCategories(JoinPoint thisJoinPoint) {
  40.         List< class > classes = new ArrayList< class >();
  41.        
  42.         // get class level categories (if any)
  43.         Class cl = thisJoinPoint.getTarget().getClass();
  44.    
  45.         addCategories((Uses) cl.getAnnotation(Uses.class), classes);
  46.        
  47.         // get method level categories (if any)
  48.         if ( thisJoinPoint.getKind().equals(JoinPoint.METHOD_CALL)) {
  49.             MethodSignature sig = (MethodSignature) thisJoinPoint.getSignature();
  50.             addCategories((Uses) sig.getMethod().getAnnotation(Uses.class), classes);
  51.         }
  52.  
  53.         return classes;
  54.     }
  55.    
  56.    
  57.     private void addCategories(Uses uses, List< class > classList) {
  58.         if ( uses != null ) {
  59.                 Class[] classes = uses.category();
  60.                 for(Class cl : classes)
  61.                     classList.add(cl);
  62.         }
  63.     }
  64. }

One thing to note when working with Annotations / Aspects in Groovy: you have to keep track of the build order. I struggled for a while to figure out why I was not seeing the annotation in my Groovy classes. It was because it had not been built yet! I ended up having to split my compilation into 4 parts:

  1. Build the Annotation
  2. Compile the Groovy code
  3. Compile my other Java code (just test code)
  4. Weave the Aspects

Design
General
Grails
Groovy
Java
Software Development
Speaking
Thought

Comments (4)

Permalink

Uncle Bob on XML

I’m trying to catch up to my overflowing Google reader, and have just seen Uncle Bob’s posting on XML “The Hidiocy of XML Languages“:

Look, writing in XML is hideous. It’s wordy, it’s error-prone, it’s arcane, it’s redundant, it’s redundant, it’s redundant, it’s… HIDEOUS! To make matters worse, we have been embedding OTHER languages INSIDE this horrible container. EGAD! YIKES! ZOUNDS! FORSOOTH! This is just plain nuts, stupid, idiotic, retarded, poo-poo-headed, silliness!

All I can say is AMEN!!! And it just gets better.

I’ve never been a fan of XML. Yes, it does have benefits as a data transfer mechanism, though even that is questionable. Take the ACORD standards as an example. This is the standard schema for defining interoperability standards for Insurance Company operations/transactions (Quotes, etc). Fair enough, this can be very useful for companies to work together. However, each insurance company has it’s own way of doing business, and may not use the schema in the same way. ie a Policy for this company (or even Line of Business) may not mean the same as for another. So, how interoperable is that?

XML sucks. Its better than binary, or — shudder — ASN.1, but it still sucks, and should not be used as a language. Thank you Uncle Bob for your rant! It makes me that maybe, just maybe, I’m not as insane as people think when I tell them that I hate writing logic in XML.

Design
General
Software Development
Thought

Comments (2)

Permalink

Simple Groovy script to remove .svn directories

The other day I needed to remove a mess of .svn directories from a project as I moved it from my personal box (using svn as the soure control) to the client’s source control system. This is a fairly frequent task, so attempting to be a “productive programmer” I decided that I would take the time to write a script to do this for me. After testing, it took about an hour to write… mainly because I tried to be too fancy, and tried a few things in Groovy I had not seen before. Overall, it was an hour well spent:

  1. search_for(“.”)
  2.  
  3. def search_for(dir) {
  4.         homedir = new File(dir)
  5.         homedir.eachDir {
  6.                 if (it.name == “.svn”) {
  7.                         println it.canonicalPath
  8.                         deleteDirectory(it)
  9.                 }
  10.                 else {
  11.                         search_for(it.canonicalPath)
  12.                 }
  13.         }
  14. }
  15.  
  16. def deleteDirectory(dir) {
  17.         dir.eachDir { deleteDirectory(it) }
  18.         dir.eachFile { it.delete() }
  19.         dir.delete()
  20. }

14 lines. I really like the eachDir and the eachFile methods on the File object… and there is even an eachFileRecurse. All I can say is: where the heck is the eachDirRecurse??? Oh well. It was still a good learning experience, and now I have a malleable tool next time I run into something similar.

General
Groovy
Java
Software Development

Comments (7)

Permalink