Over a million developers have joined DZone.

Combining Gradle with Antlr3

DZone's Guide to

Combining Gradle with Antlr3

· Java Zone
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

I've been going through a relatively painless process of converting Tapestry from Maven to Gradle, and am thrilled with the results. My biggest stumbling point so far was Tapestry's use of Antlr3 for its property expression language.

The built-in support for Antlr only went as far as Antlr2. The Maven plugin I had been using understood Antlr3. After a bit of research and hacking, this is what I came up with as a solution for Tapestry:

description="Central module for Tapestry, containing all core services and components"

antlrSource = "src/main/antlr"
antlrOutput = "$buildDir/generated-sources/antlr"

configurations {

sourceSets.main.java.srcDir antlrOutput

dependencies {
compile project(':tapestry-ioc')
compile project(':tapestry-json')

provided project(":tapestry-test")
provided "javax.servlet:servlet-api:$servletAPIVersion"

compile "commons-codec:commons-codec:1.3"

// Transitive will bring in the unwanted string template library as well
compile "org.antlr:antlr-runtime:3.3", { transitive = false }

// Antlr3 tool path used with the antlr3 task
antlr3 "org.antlr:antlr:3.3"

// This may spin out as a plugin once we've got the details down pat

task generateGrammarSource {
description = "Generates Java sources from Antlr3 grammars."
inputs.dir file(antlrSource)
outputs.dir file(antlrOutput)
} << {

// Might have a problem here if the current directory has a space in its name

def grammars = fileTree(antlrSource).include("**/*.g")

ant.java(classname: 'org.antlr.Tool', fork: true, classpath: "${configurations.antlr3.asPath}") {
arg(line: "-o ${antlrOutput}/org/apache/tapestry5/internal/antlr")
arg(line: grammars.files.join(" "))

compileJava.dependsOn generateGrammarSource

The essence here is to create a configuration (a kind of class path) just for running the Antlr Tool class. The new task finds the grammar files and feeds them to the tool. We also thread the output of the tool as a search path for the main Java compilation task. Finally, we define the inputs and outputs for the task, so that Gradle can decide whether it is necessary to even run the task.

Part of the fun of Gradle is that it is still a Groovy script, so there's a familiar and uniform syntax to defining variables and doing other non-declarative things, such as building up the list of grammar files for the Tool.

As you might guess from some of the comments, this is something of a first pass; the Maven plugin was a bit better at assembling the list of input file names in such a way that the Antlr3 Tool class knew where to write the output Java source files properly; if Tapestry used a number of grammars in a number of different locations, the solution above would be insufficient. It also seems roundabout to use Ant to launch a Java application ... I didn't see an easier way (though I have no doubt its hidden inside the Gradle documentation).

My experience getting this working was mostly positive; there's a very large amount of documentation for Gradle that helped, though it can be a bit daunting, as the information you need is often scattered across a mix of the Gradle DSL reference, the User Guide, the Javadoc and the GroovyDoc. Too often, it feels like a solution is only understandable once finished, working backwards from some internal details of Gradle (such as which exact classes it chooses to instantiate in a given situation) back through the various interfaces, Java classes, and Groovy MetaObject extensions to those classes.

In fact, key parts of what I did ultimately accomplish were discovered through web searches, not in the documentation. But, that also means that the system works.

Of course, this is the pot calling the kettle black ... one criticism of Tapestry can be paraphrased as we can customize it to do anything, and in just a few lines of code, but it can take three days to figure out where those lines of code go.

At the end of the day, I'm much happier with Gradle; the build process is faster, the build scripts are tiny and much, much easier to maintain, and the feedback from the tool is excellent. There's still many more issues to work out ... mostly in terms of Apache and Maven infrastructure:

  • Ensuring the Maven artifacts are created properly, with the right dependencies in the generated pom.xml
  • Generating a Maven archetype using Gradle
  • Generating JavaDoc and Tapestry component documentation with Gradle, along with a minimal amount of pages to link it together (akin to the Maven site plugin)
  • Generating source and binary artifacts and getting everything uploaded to the Apache Nexus properly

Regardless, I think all of these things will come together in good time. I'm not going back, and dearly hope to never use Maven again!

From http://tapestryjava.blogspot.com/2011/03/combining-gradle-with-antlr3.html

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat


Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}