Yesterday evening I fooled around with gradle quite a bit, finally sitting down and taking some time to learn it as I’ve been hearing lots of good things about it. And man, I like it!
I decided to use it to build the kind of project that enterprise architects go ga-ga over: a multi module project that contains a shared module with an interface (containing JAXWS annotations), a services war module to create a service implementation, and a client implementation to call it. It was a breeze and I finished it in a couple hours.
For starters, I created a root directory and created the following build.gradle and settings.gradle file in it:
build.gradle:
subprojects {
usePlugin 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.7'
}
group = 'org.jamescarr'
version = '1.0'
sourceCompatibility=1.6
}
dependsOnChildren()
settings.gradle:
include "shared", "api", "services"
Running gradle build from this directory will auto-create your directories for you. I went ahead and created the source directories and build.gradle for each module myself, but there are ways to make your script do that too, more on that in another post.
In our shared project, there’s really no dependencies, so the build.gradle file is left blank. We just create the following interface under src/main/java:
package org.jamescarr;
import javax.jws.WebService;
import javax.jws.WebParam;
import javax.jws.WebMethod;
@WebService
public interface Greeter{
String getGreetingFor(@WebParam(name="greetee") String greetee);
}
Nothing fancy. Now let’s make the service. Foremost, it’ll need to depend on shared since it’s going to have the actual implementation in it. We’ll also depend on CXF to setup the cxf servlet as well as use the war and jetty plugins so we can produce a war artifact and the jetty plugin for running it locally.
services/build.gradle:
usePlugin 'war'
usePlugin 'jetty'
dependencies {
compile project(':shared')
compile 'org.apache.cxf:cxf-bundle-minimal:2.2.6'
}
At this point, doing a gradle build will auto generate your src/main/webapp directory, and if you throw an index.html file in there and run gradle jettyRun your server will start up and you can navigate to http://localhost:8080 to see it.
Now let’s write our Greeter implementation.
src/main/java/org/jamescarr/EnglishGreeter.java:
package org.jamescarr;
import javax.jws.WebService;
@WebService(endpointInterface="org.jamescarr.Greeter", serviceName="GreetingService")
public class EnglishGreeter implements Greeter{
@Override
public String getGreetingFor(String greetee){
return "Hello " + greetee;
}
}
Next we need to add a web.xml to src/main/webapp/WEB-INF and an application-context.xml file under src/main/resource. Since this is the part where it get’s ugly, I’m simply going to link to them on github… you can see them here and here.
Now if we go the root of the services directory and run gradle jettyRun our server will be up and running and if you navigate to http://localhost:8080/services/services (if I had named the module something else it wouldn’t look so silly) you should see the generated CXF page listing the available services, and Greeter -> getGreetingFor will be listed. Now let’s create the client and start communicating with the service!
In the client, we’re just going to create a quick client using JaxWsProxyFactory directly, but in most projects you might configure this in spring and inject it using the service interface. So we’ll need to depend on our shared project for the interface and cxf for the proxy factory. We’ll also setup a task named “run” to simply run this from the commandline and see the output.
api/bild.gradle:
dependencies {
compile project(':shared')
compile "org.apache.cxf:cxf-bundle-minimal:2.2.6"
}
task run(dependsOn:'build') <<{
ant.java(classname: 'org.jamescarr.Main', fork: false,
classpath: "${sourceSets.main.runtimeClasspath.asPath}")
}
The run task depends on the build task, so we can ensure it builds the project before trying to run it. We also set fork to false on the ant.java task so we can see the System.out.println I'll put in the main class to print the result out. Okay, now let's whip the java class real quick:
api/src/main/java/org/jamescarr/Main.java
package org.jamescarr;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.jamescarr.Greeter;
public class Main{
public static void main(String... args){
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("http://localhost:8080/services/services/english");
factory.setServiceClass(Greeter.class);
Greeter client = (Greeter)factory.create();
System.out.println(client.getGreetingFor("James"));
}
}
I don't want to get too deep into the intricacies of CXF, but all this does is create a proxy factory for our endpoint and generates a client object that we can use to call it.
Now to finally see all this work, drop down to the commandline in the api directory and type gradle -q run. If everything works well, you should see "Hello James" printed to the console. A perfect Hello World example bringing together SOA and the pure awesomeness of gradle.
Hope you enjoyed it, if you want to take a look at the code and tinker with it hands on, feel free to clone it from github.

