Monday, November 12, 2012

Using WSDLToJava with Gradle

I currently need to generate some java sources from a wsdl with Gradle. In Maven, I've done this using the cxf-codegen-plugin but I want to avoid using anything that's maven in my new build. And there's several resources out there who will either tell you to call WSDLToJava via cxf's ant task or directly. The 'direct' way still leaves you with several possibilities like calling ProcessBuilder from your Gradle Task or using a JavaExec Task. I went for the last.

So I started piecing everything together and suddenly the build ran trough my generateJavaFromWsdlDeps and failed at compiling my sources that use the generated ones. Great, I thought but wait! I haven't even supplied a wsdl location to the JavaExec task yet. Scroll up a few lines and there's a nice error message from WSDLToJava where it complains about that exact point.

Hm, so Gradle surely ignores the exit value of a JavaExec task? Oh no it doesn't! JavaExec and subsequently the whole build always failed until I've fixed the classpath for this task (frontend and databinding were missing in the beginning). So after a little println of "configurations.generateJavaFromwsdlDepsDeps.asPath" and running the "java org.apache.cxf.tools.wsdlto.WSDLToJava" command myself and then looking at the exit value of the java process via "echo $?", which left me with a "0" - it was clear that this is a WSDLToJava bug (Or I'd consider it to be a bug).

But I won't wait for the next cxf version with a fix in it, I want a solution now and this is what I've come up with: JavaExec allows to change the standard In/Out/Err and so I set the StdErr to be a TeeOutputStream that goes to System.err and to a ByteArrayOutputStream of my own. Then parse my BAOS for errors and fail the build if there are any.

So here's the solution I went with, I think it's pretty nice. The "parsing" of stderr could probably be better (for example fail even if a single byte is written to stderr? since I don't know WSDLToJava's internals I don't know how it behaves exactly.

The whole thing does require some extra boilerplate since commons-io which I use here, must be on the build script's own classpath or else this won't work.

Loading ....

You can do this on the 'root' level of your script. I use it for a subproject so imagine the rest of the code below is wrapped in a "project(':some:sub:project')".

We first need to set up a configuration, this means we just access it inside a configurations closure and then set the dependencies like this:

Loading ....

Now we need to specify our generate task. The configuration part just configures the task itself. And in the "doLast" part we do the actual verification of the standart error stream (If you don't understand the difference, have a look at Anatomy of a Gradle Task: Execution Time). One thing I'd like to point out is, that the TaskExecutionException seems to be the only Exception that properly stops the build and it requires a reference to the failing task and a cause. To get the failing task, which is basically 'this' or 'self' or however you'd want to call it, we can't use this but need to locate the task via its name in the project as outlined in the chapter "Locating Tasks" of the gradle docs (or you could hardcode it as ':some:sub:project:generateJavaFromWsdl but that will backfire once you change the name of your task).

Loading ....

And that's it! The build fails with a nice error message. Now it's time to move on and actually make the WSDLToJava task generate some sources.

Wednesday, November 7, 2012

Anatomy of a Gradle Task: Task Dependencies

Here's another little "gotcha" on gradle tasks. When they're triggered. I've seen quite a few posts on stackoverflow along the lines of "How can I call a gradle task". You can't (Well ok you could but you don't want to). It is executed as a dependency of another task.

Going back to that little copy task I wanted to execute, I needed it to run roughly somewhere after the clean task and before jar task. I ended up making my copy task dependent of compile. That didn't work so I tried compileJava and classes and... only to later realize that the dependency was in the wrong direction: My task depends on one that is being executed but that doesn't trigger my task, it merely states that my task, should it be executed, can only be run after some other task.

So let's revert the direction of the dependency. There are several ways to do this and I don't know if there's a best practice. Here are a few variations:

Loading ....
Loading ....
Loading ....
Loading ....

I currently use the first variation because my task is standalone and I only need to define the task dependencies. However, the jar.doFirst approach has its appeal too since it's nice and short. I'm just reluctant to manipulate the logic of an existing task provided by a plugin.

What I haven't figured out yet, is how to put the task into a variable and have the ability to reuse it for several modules of my projects.

Anatomy of a Gradle Task: Execution Time

So I'm trying out gradle in the hope of being able to simplify and streamline an existing maven build which is quite large and inconsistent. And I just spent some time to figure out a few gotcha about gradle tasks and this post is to help others understand, because I think the gradle docs aren't clear enough on this point

What I wanted to achieve is, to copy all *.properties files in src/main/java to the resources-output directory so they are included in the jar, because javac won't pick them up since they're no java source files. What happened was that, depending on what approach I tried, sometimes the copy worked sometimes it didn't and I couldn't understand why.

Except for the first example in the gradle docs, which uses doLast, each example uses "<<". Compare the following two equivalent definitions of the hello task.

Loading ....

Let's dissect it real quick. We have a Closure that prints "Hello World". In the first example, it is passed as a parameter to the "doLast" method of the Task (Remember: methods in groovy can be called without parentheses so it's equivalent to "doLast({...})" which should make the method call clear). I suspect this method appends the closure to some ordered collection for later execution. The second example that uses "<<" uses an overloaded operator which in the end just calls doLast and ends up having the same effect. This Closure, and that's the important thing to take away here: is executed at build time.

Compare this with this third example which is like the first but without the "doLast" part.

Loading ....

This snippet, however, will print "Hello World" right away since it is executed at configuration time.

So putting it all together, my copy ended up looking like this (printlns will be removed or replaced with logging later):

Loading ....

This will configure the copy task right away (all the paths seem precalculated at he beginning so referencing them at configure time is save).

To conclude: The "<<" shortcut is great in some situations but I think it can be quite dangerous since it's just 2 characters that separate two entirely different behaviours. So the gradle syntax is terse and expressive but you really have to understand what you're intending to do and also be mindful of what a task does when reading a gradle script, since the differences can be quite subtle.

Update: The Javadoc of the Task actually describes this and probably much better than I can

.