简体   繁体   中英

Groovy AST transformation - How to compile java annotated class with Gradle and Intellij IDEA

I want to develop a Groovy AST transformation to add some methods on certain classes. So I write an annotation class and corresponding transformation class. Then I annotate a java class with my Groovy AST annotation.

When I compile the java annotated class with embedded groovy compiler (for example by this snippet: Class enhancedClass = new GroovyClassLoader().parseClass(new File("...")); ), the transformation is performed and methods are added to the compiled class which is called enhancedClass in the snippet.

But I cann't compile the java class with Gradle groovy plugin and Intellij IDEA correctly.

QUESTION: Can everyone help me to working with Groovy AST transformation in Gradle and Intellij IDEA?

NOTE 1: I use Intellij IDEA 14 ultimate edition.

NOTE 2: My Groovy AST classes and the java annotated class and my "build.gradle" file are somethings like the followings:

Annotation class:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@GroovyASTTransformationClass(classes = {MyASTTransformation.class})
public @interface MyAST {
}

and Transformation class:

@CompileStatic
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
public class MyASTTransformation implements ASTTransformation {
   @Override
   public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
      ...
   }
}

The java annotated class:

@MyAST
public class A {
   ...
}

The "build.gradle" file:

apply plugin: 'groovy'
sourceSets {
    main {
       groovy {
          srcDirs = ['src/main/groovy', 'src/main/java']
       }
        java {
          srcDirs = []
      }
   }
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.4'
}

I created my first custom AST transformation and I also ran into similar issues so sharing my limited experience. I'm using Groovy 2.4.7 and IntelliJ IDEA 2016.3.2. I was only able to use the custom transform annotation if:

  1. It was created as a separate artifact (project) and another project that was using the annotation referenced it.
  2. Ran a Groovy test script in the same project as the custom AST transformation code that ran a GroovyShell with Groovy code that used the custom annotation.

I had first attempted doing it in the same project but that didn't work. I believe it's because the AST transformation occurs at compile time. Here's my example:


AST transformation project

Annotation

@Retention (RetentionPolicy.SOURCE)
@Target ([ElementType.TYPE, ElementType.METHOD])
@GroovyASTTransformationClass (classes = [SqlAssistTransform])
@interface SqlAssist {
}

Transformation

@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
class SqlAssistTransform extends AbstractASTTransformation {
...
}

settings.gradle

rootProject.name = 'groovy-sql-transform'

build.gradle

...
group = 'com.company.groovy.transform'
version = '1.0-groovy-2.4'
description = 'Groovy AST transformation for SQL syntax'
...

Project using AST annotation

Annotated class

@SqlAssist
class Something {
...
}

Dependency example #1 - dependency on AST artifact from repository

build.gradle

 ... dependencies { ... // As long as your local repository (or remote repository) has the AST transformation project installed. ie Run '.\\gradlew install' in AST project to install to local repository compile group:'com.company.groovy.transform', name:'groovy-sql-transform', version: '1.0.0-groovy-2-4' ... } ...

Dependency example #2 - dependency on AST project

build.gradle

 ... dependencies { ... compile project(':groovy-sql-transform') ... } ...

settings.gradle

 rootProject.name = 'project-name' // Assumption that AST project lives at the same level as this project include "groovy-sql-transform" project(":groovy-sql-transform").projectDir = new File("../groovy-sql-transform")

Testing

I didn't create a proper unit test, but I did use the following to test and debugged in IntelliJ so I could look at the AST in different places in my AST transformation code. Example test Groovy script that I had within the AST transformation project:

new GroovyShell(getClass().classLoader).evaluate '''

import com.company.groovy.transform.SqlAssist

@SqlAssist
class Testing {
...
}

'''

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM