Chapter 3. Code-level integration

This chapter covers

  • Calling Groovy scripts from Java using JSR 223
  • Calling Groovy scripts from Java using Groovy library classes

In chapter 1 I reviewed many of Java’s arguable weaknesses and drawbacks and suggested ways that Groovy might help ameliorate them. Because that chapter was intended to be introductory, I only suggested how Groovy can help, without showing a lot of code examples.

This chapter begins an examination of Java and Groovy integration in detail. In this chapter I’ll start using Groovy and Java together in fundamental ways, without worrying about frameworks or addressing any particular use case. A guide to the techniques discussed in this chapter is shown in figure 3.1.

Figure 3.1. Guide to integration features. Groovy can be accessed with Java classes alone using the JSR 223 script engine. If you are willing to add some Groovy library classes to Java, the Eval, GroovyShell, and Binding classes make working with scripts easy. The best way to combine Groovy and Java is using classes for both languages.

3.1. Integrating Java with other languages

Combining Java with other languages has always been a challenge. Java historically hasn’t played well with others.[1] The only API designed from the beginning for Java to call functions written in other languages is JNI, the Java Native Interface, which is awkward to use even in the best of circumstances.[2] The past few years, however, have seen the rise of entire families of languages that compile directly to bytecodes that run on the JVM, from Groovy to Scala to Clojure, as well as bridge languages like Jython or JRuby that allow you to run code written in Python or Ruby on the JVM. From the point of view of these “alternative” JVM-based languages, Java’s real contribution isn’t the language itself, but rather the virtual machine and the associated Java libraries. JVM-based languages take advantage of the Java infrastructure and try to handle any Java-specific drawbacks.

1 Of course, this is true of most languages.

2 Once, back in the late 1990s, I had to build a Java Swing user interface in front of an engineering system written in Fortran. I used JNI to go from Java to C and then from C to Fortran. The results were like putting a notch into a wooden beam and saying, “I want you to break right here.”

JVM

Ultimately, Java’s biggest contribution isn’t the language; it’s the virtual machine.

Whenever a new capability is integrated into Java’s basic infrastructure, a Java Specification Request (JSR) is created to provide a standard implementation mechanism. In the integration case, the JSR in question is JSR 223, Scripting for the Java Platform (http://jcp.org/en/jsr/detail?id=223). The purpose of the JSR is to allow other (presumably scripting) languages to be invoked from Java. Although most of this book will assume that you’re mixing Java and Groovy on a class-by-class basis, for the sake of completeness I’ll review here how to call a Groovy script from Java, both using the JSR technique and using library classes provided by Groovy for that purpose.

Groovy is much closer to Java than the script integration story suggests, however. As I’ll demonstrate in the section on calling Java from Groovy rather than the other way around, virtually every Groovy program of any size uses Java already. Groovy code can instantiate a Java class, call a method Groovy added to it (the so-called Groovy JDK highlighted in chapter 4, section 4.3), and call additional Java methods on the result. The question then becomes, what does Groovy bring to Java? How can you simplify your development tasks by adding Groovy to Java systems? I’ll address that question in the rest of the chapter (and, indeed, in the rest of the book). Let’s start, though, with the scripting story. How do you combine Java and Groovy in the same system when Groovy consists of scripts rather than classes, and you want to isolate any Java integration code?

3.2. Executing Groovy scripts from Java

The assumption in the first couple of sections of this chapter is that you’ve written or acquired some Groovy scripts and wish to use them in your Java system in a way that’s minimally invasive. Perhaps you’re using the scripts to implement business logic in Groovy because it changes so frequently (a technique referred to as Liquid Heart by Dierk Koenig, lead author of Groovy in Action [Manning, 2007]). Perhaps you’re replacing Perl scripts with Groovy because anything you can do in Perl you can do in Groovy, with the added bonus that you can integrate with existing Java systems. Perhaps you’re following one of the original intents of the JSR, which is to use a scripting language to generate user interfaces while letting Java handle the back-end functionality. In any case, I want to demonstrate how to invoke those scripts from a Java system as easily as possible.

One of the interesting features of Groovy is that, unlike in Java, you don’t have to put all Groovy code into a class. You can just put all your Groovy code into a file called practically anything you like, as long as the file extension is .groovy, and then you can execute the scripts with the groovy command. One possible sweet spot for Groovy is to write short, simple programs without the clutter of creating a class with a main method in it, and here I’ll show how to incorporate scripts like that into a Java application.

In keeping with the standard I’ll start with a technique based on JSR 223, Scripting for the Java Platform, which allows you to invoke Groovy purely from Java library calls. Then I’ll show that if you use a couple of classes from the Groovy API you can simplify the integration. Finally, I’ll show that if you can change from scripts to classes for your Groovy code, nearly all the complexity can be eliminated.

Incidentally, assuming any Groovy scripts are compiled, at runtime treat the combined application as though it’s all Java. All the integration strategies I plan to discuss in this chapter involve deciding where and how to use Groovy to make your life easier. Once you have the combined system, though, the deployment story is really simple, as the sidebar demonstrates.

Groovy and Java together at runtime

At runtime, compiled Groovy and compiled Java both result in bytecodes for the JVM. To execute code that combines them, all that’s necessary is to add a single JAR file to the system. Compiling and testing your code requires the Groovy compiler and libraries, but at runtime all you need is one JAR.

That JAR comes with your Groovy distribution in the embeddable subdirectory. Suppose, for example, your Groovy installation is version 2.1.5. Then on your disk in the Groovy installation directory you have the structure shown in the following figure, and the JAR file you need is groovy-all-2.1.5.jar.

Add the groovy-all JAR to your system, and you can run it with the java command.

In the rest of the text, I’ll refer to this JAR file as the “groovy-all” JAR. If this JAR is added to your classpath you can execute combined Groovy and Java applications with the standard java command. If you add a Groovy module to a web application, add the groovy-all JAR to the WEB-INF//lib directory and everything will work normally.

Here’s a minimal demonstration just to prove the point. Consider the “Hello, World!” application written in Groovy, which, unlike in Java, is a one-liner:

println 'Hello, Groovy!'

If I saved this into a file called hello_world.groovy I could execute the script using the groovy command, which would compile it and run it all in one process. To run it using the java command, however, first I have to compile it with groovyc and then execute the resulting bytecodes, making sure the groovy-all JAR is in the classpath. The two-step process is shown. Note that the java command should be all on one line:

> groovyc hello_world.groovy
> java –cp
    .:$GROOVY_HOME/embeddable/groovy-all-2.1.5.jar
    hello_world
→ Hello, Groovy!

I needed the groovyc command in order to compile the script, but I was able to execute it using plain old java (as long as the groovy-all JAR was in the execution classpath).

At the API level, to call a Groovy script from Java you have a few alternatives. I’ll first show the “hardest” way possible, using the JSR-223 API. The API associated with JSR 223 is designed to allow Java programs to invoke scripts written in other languages.

I’m calling this “the hard way” because it doesn’t take advantage of anything provided by Groovy other than the script itself. I’ll use the layers of indirection provided by the Java API, which separates the Groovy code from the Java code that invokes it. Later you’ll start mixing Java and Groovy by combining classes and methods, and you’ll find that’s much easier. Still, it’s worth seeing how to use the JSR, especially because, after all, it is the standard. Also, even if it’s technically the hard way, it’s really not all that hard.

3.2.1. Using JSR223 scripting for the Java Platform API

Built into Java SE 6 and above, the API for JSR 223, Scripting for the Java Platform, is a standard mechanism you can use to call scripts written in other languages. The advantage to this approach is that it avoids introducing anything specific to Groovy into the calling Java program. If you already have Groovy scripts and you just want to call them from inside Java, this is a good way to go.

JSR 223

The JSR allows you to call Groovy scripts using purely Java classes.

The JSR defines an API based on a javax.script.ScriptEngine instance. As is common with many Java libraries, the API also includes a factory interface, in this case called javax.script.ScriptEngineFactory, for retrieving ScriptEngine instances. The API also specifies a javax.script.ScriptEngineManager class, which retrieves metadata about the available ScriptEngineFactory instances.

In many Java APIs you use a factory to acquire the object you need. For example, parsing XML with a SAX parser is done by first getting an instance of the SAXParserFactory and then using it to acquire a new SAX parser. The same is true for DOM builders, XSLT transformation engines, and many others. In each case, if you want to use a particular implementation other than the built-in default, you need to specify an environment variable, a method argument, or some other way of letting Java know you’re planning to do something different. You also need to make the alternative implementation available in your classpath.

The first issue, therefore, is to determine whether the script engine used for Groovy code is available by default and, if not, how to acquire it. Using the Java 7 JDK from Oracle I can determine which factories are already embedded. The following listing retrieves all the available factories from the manager and prints some of their properties.

Listing 3.1. Finding all the available script engine factories

With a nod toward better practices than simply using System.out.println statements, I set up a simple logger. Then I retrieved all the available factories from the manager and printed the language name and engine name. Finally, I printed all the available names for each factory, which shows all the available aliases that can be used to retrieve them.

The results are shown here, truncated for readability:

INFO: lang name: ECMAScript
INFO: lang version: 1.8
INFO: engine version: 1.7 release 3 PRERELEASE
INFO: engine name: Mozilla Rhino
INFO: [js, rhino, JavaScript, javascript, ECMAScript, ecmascript]

The output shows that by default there’s only one factory available, and its purpose is to execute JavaScript (or, more formally, ECMAScript). This factory can be retrieved using any of the names on the last line, but there’s only one factory available, and it has nothing to do with Groovy.

Fortunately, making a Groovy script engine factory available is easy. One of the features of the ScriptEngineManager class is that it detects new factories using the same extension mechanism used for JAR files. In other words, all you have to do is to add the Groovy libraries to your classpath via the groovy-all JAR. Once you do that, the same program produces the additional output shown here:

INFO: lang name: Groovy
INFO: lang version: 2.1.3
INFO: engine version: 2.0
INFO: engine name: Groovy Scripting Engine
INFO: [groovy, Groovy]

In this case the script engine reports that the Groovy language version is 2.1.3 and the engine version is 2.0.[3]

3 I did use the Groovy 2.1.5 compiler, but the script engine still reports 2.1.3. It doesn’t affect the results, though.

In this particular API, even though a factory is now available, you don’t need to use it to acquire the script engine. Instead, the ScriptEngineManager class has a method to retrieve the factory by supplying its name (either groovy or Groovy, as shown in the previous output) in the form of a String. From the ScriptEngine I can then execute Groovy scripts using the script engine’s eval method. The process is illustrated in figure 3.2.

Figure 3.2. Using the JSR 223 ScriptEngine to invoke a Groovy script. Java creates a ScriptEngineManager, which then yields a ScriptEngine. After supplying parameters to the engine, its eval method is invoked to execute a Groovy script.

The next listing demonstrates the API in action in a simple “Hello, World!” Groovy script.

Listing 3.2. Using the ScriptEngine to execute a simple Groovy script

I retrieve the Groovy script engine by calling the getEngineByName method. I then use two different overloads of the eval method: one that takes a String argument and one that takes an implementation of the java.io.Reader interface. In the first case, the supplied string needs to be the actual scripting code. For the reader, though, I use a FileReader wrapped around the “Hello, Groovy!” script. The output is what you would expect in each case.

Supplying Parameters to a Groovy Script

What if the Groovy script took input parameters and returned data? In the Groovy scripting world this is handled through a binding. When I discuss the GroovyShell in the next section I’ll show that there’s actually a class in the Groovy API called Binding, but here I’ll do the binding implicitly through the Java API.

A binding is a collection of variables at a scope that makes them visible inside a script. In the JSR 223 API, the ScriptEngine class itself acts as a binding. It has both a put and a get method that can be used to add variables to scripts and retrieve the results from them.

To illustrate this, let’s do something a bit less trivial and possibly more practical. Instead of doing a simple “Hello, World!” script, consider the Google geocoder, in its version 2 form.

Groovy Sweet Spot

Groovy scripts are an easy way to experiment with new libraries.

A geocoder is an application that converts addresses to latitude/longitude pairs. Google has had a publicly available geocoder for years. In this section I’ll use version 2, which requires a key (available through a free registration), but which gives me the chance to show some interesting Groovy features. When I discuss XML processing later in this chapter I’ll use version 3 of the geocoder instead. That version no longer requires a key, but it doesn’t make the results available in the same comma-separated form I’ll use here.

The documentation for version 2 of the Google geocoder can be found at http://mng.bz/Pg8S. Version 2 is currently deprecated but still works. I’m using it here because it’s familiar from the previous chapter, so you can focus on the input/output parts of the script, and because it also lets me demonstrate multiple return values.[4]

4 Another reason to show the version 2 geocoder is because the Google Maps API for Android still uses it.

In order to use the geocoder, the basic idea is to transmit an address as a parameter in an HTTP GET request and process the results. As shown in chapter 2, using the Google geocoder takes the following steps:

1.  Convert a list containing the street, city, and state into a URL-encoded string whose values are separated by “,”.

2.  Convert a map with the key’s address and sensor into a query string.

3.  Transmit the resulting URL to the Google geocoder.

4.  Parse the results into the desired values.

The first step uses the collect method from Groovy, which takes a closure as an argument, applies the closure to each element of a collection, and returns a new collection containing the results. I take the resulting collection and joined each of its elements into a single string, using “,” as a separator:

String address = [street,city,state].collect {
    URLEncoder.encode(it,'UTF-8')
}.join(',')
Undeclared variables

The street, city, and state are not declared in the script. This adds them to the binding, making them available to the caller.

To build a query string I add all the required parameters to a map called params. I’m also requesting comma-separated values for the output, which is not available in the version 3 geocoder:

def params = [q:address, sensor:false, output:'csv', key:'ABQIAAAAaUT...']

The value of sensor should be true if this request is coming from a GPS-enabled device and false otherwise. The key is determined at registration (version 3 doesn’t require a key). The output is here set to CSV, so that the result is a string of comma-separated values composed of the response code (hopefully 200), the magnification level, and the latitude and longitude.

To convert the map into a query string, the collect method is used again. On a map, if a collect is applied with a two-argument closure, the method automatically separates the keys from the values. What I want here is to replace expressions like key:value with strings like key=value. The complete URL is then found by concatenating the query string to the base URL:

String url = base + params.collect { k,v -> "$k=$v" }.join('&')

Finally, I take advantage of the Groovy JDK. In the Groovy JDK the String class contains a method called toURL, which converts the String into an instance of java.net.URL. The URL class in the Groovy JDK includes a getText method, which I can invoke as a text property.

Property access

In Groovy, the standard idiom is to access a property, which is automatically converted to a getter or setter method.

The code to retrieve the desired CSV string is

url.toURL().text

Now I can use the split method on String, which divides the string at the commas and returns a list containing the elements. I can then take advantage of Groovy’s cool multivalued return capability to assign each value to an output variable.

The complete script is shown next and displayed graphically in figure 3.3:

String address = [street,city,state].collect {
    URLEncoder.encode(it,'UTF-8')
}.join(',+')
def params = [q:address,sensor:false,output:'csv',key:'ABQIAAAAaUT...']
String base = 'http://maps.google.com/maps/geo?'
String url = base + params.collect { k,v -> "$k=$v" }.join('&')
(code,level,lat,lng) = url.toURL().text.split(',')
Figure 3.3. The Groovy script for accessing the Google V2 geocoder

Running this script requires me to supply the street, city, and state information, and then retrieve the output latitude and longitude. I want to use Java to supply the input values and process the output, but first I’ll show a typical result, which can then be used as a test case. To avoid being too U.S.-centric I’ll use the address for the Royal Observatory in Greenwich, England. That makes the values for street, city, and state “Blackheath Avenue,” “Greenwich,” and “UK,” respectively.[5] Executing the script results in the output

5 Clearly the word “state” is to be interpreted broadly. Supply a country name for state, and it works all over the world.

(code,level,lat,lng) = (200,6,51.4752654,0.0014324)

The Royal Observatory was originally the arbitrarily chosen location of the prime meridian, so the value of the longitude should be pretty close to zero, and it is. The input address isn’t as precise as it might be, and the observatory address doesn’t define the actual prime meridian any more, but the results are pretty impressive anyway. The resulting test case as part of a JUnit 4 test is shown in the next listing.

Listing 3.3. A JUnit test case to check the JSR 223 script engine results

The result is the same as running the Groovy script by itself using Groovy. Setting the values of the input variables is trivial. The output variables need to be cast to the String type and then converted to doubles, but again the process is straightforward. If your goal is to execute an external Groovy script from Java without introducing any Groovy dependencies at all (other than adding the groovy-all JAR to your classpath), this mechanism works just fine.

In the next section I want to relax that requirement. If you’re willing to use some classes from the Groovy standard library, life gets simpler.

3.2.2. Working with the Groovy Eval class

There are two special classes in the Groovy library, groovy.util.Eval and groovy .lang.GroovyShell, specifically designed for executing scripts. In this section I’ll show examples using the Eval class, and in the next section I’ll show GroovyShell. In each case, the goal is still to invoke external Groovy scripts from Java.

The Eval class is a utility class (all its methods are static) for executing operations that take none, one, two, or three parameters. The relevant methods are shown in table 3.1.

Table 3.1. Static methods in groovy.util.Eval for executing Groovy from Java
Eval.me Overloaded to take a String expression or an expression with a String symbol and an Object
Eval.x One argument: the value of x
Eval.xy Two arguments, x and y
Eval.xyz Three arguments, x, y, and z

To demonstrate the methods I’ll add additional tests to the JUnit test case. The test is written in Java, so I’ll automatically call Groovy from Java.

The following listing shows four tests, one for each of the static methods in the Eval class.

Listing 3.4. JUnit 4 test class verifying results of calling Eval methods from Java

In each test the Groovy script to be evaluated is included as a string. Unlike the ScriptEngine there’s no overload for instances of Reader, so to execute a script in a separate file would require reading the file into a string. The methods also assume that the input variables are called x, y, and z, which might be asking too much. Still, it’s interesting that this mechanism exists at all.

In addition to illustrating the mechanics of calling Groovy scripts from Java, the tests also demonstrate operator overloading in the String class. The minus operator in Groovy corresponds to the minus method in String. Its implementation to remove the first instance of its argument from the given string is used with strings to remove instances of substrings. In Groovy, strings can be contained within either single or double quotes. Single-quoted strings are regular Java strings, and double-quoted strings are parameterized strings, diplomatically called Groovy strings, but formally called, unfortunately, GStrings.[6]

6 To make matters worse, simple parameters are injected into GStrings using a dollar sign. This has led to far too many “insert a $ into a GString” jokes. To me, this is a clear demonstration that we don’t have enough women in computer science. Don’t you think that if there had been one woman on the team at the time, she could have said, “Hey, that’s a funny joke, but let’s not build it into the standard library that’s going to be used by everybody forever?” After all, it’s hard enough to get a language named Groovy taken seriously by the Fortune 500 without going there, too. For my part, I call them Groovy strings, which is what the class should have been called all along. It is a funny joke, though—for about 10 minutes.

The process of using Eval from Java is shown in figure 3.4.

Figure 3.4. Java calls the me, x, xy, or xyz method in the Groovy Eval class to execute a script.

The Eval class is convenient and simple, but often it’s too simple. It rests on a more powerful foundation, the GroovyShell class, which I’ll discuss next.

3.2.3. Working with the GroovyShell class

The GroovyShell class is used for scripts that aren’t restricted to the special cases described in the previous section on Eval. The class groovy.lang.GroovyShell can be used to execute scripts, particularly when combined with a Binding.

Unlike Eval, the GroovyShell class does not contain only static methods. It needs to be instantiated before invoking its evaluate method. As a simple example, consider adding the following test to the previous set of test cases:

@Test
public void testEvaluateString() {
    GroovyShell shell = new GroovyShell();

    Object result = shell.evaluate("3+4");
    assertEquals(7, result);
}

The evaluate method is heavily overloaded. The version I’m using here takes a string representing the script to be evaluated. Other overloads take a java.io.File or a java.io.Reader instance, with various additional arguments. There are overloads that take a java.io.InputStream as well, but they’re deprecated due to possible encoding issues.

So far, using the GroovyShell looks a lot like using the ScriptEngine class, though you can instantiate it directly in this case. To deal with input and output variables, however, the GroovyShell uses the groovy.lang.Binding class to provide a map of input and output variables.

The next listing shows the Binding and GroovyShell classes in action. It’s another test to add to the growing JUnit 4 test case.

Listing 3.5. Using GroovyShell and Binding to invoke the Google geocoder

Passing parameters into the script is easy enough using the setVariable method on the Binding. The binding is then used as an argument to the GroovyShell constructor. The script is run from Java using the evaluate method as usual, and the results are extracted by getting the output variables from the shell. Using a GroovyShell and Binding is illustrated in figure 3.5.

Figure 3.5. Java code sets variables in the Binding, which is used in the GroovyShell to execute Groovy code. The results are returned via the getVariable method in the Binding.

There’s more to the GroovyShell than I’m presenting here. I can use the parse method, rather than evaluate, to parse the script and retrieve a reference to the generated Script object. That way I can set the binding variables and rerun the script without having to recompile every time. GroovyShell also works with a hierarchy of classloaders and configurations. Allthough all of that is interesting, it doesn’t really add a lot to the integration story, so I’ll refer you to Dierk Koenig’s most excellent Groovy in Action for details.

The Hard Way

Use the ScriptEngine class from Java, or the Eval and GroovyShell classes from Groovy, along with a Binding if necessary, to call Groovy scripts from Java.

Between the ScriptEngine, Eval, and GroovyShell classes, hopefully you’ll agree that there are a variety of ways to execute Groovy scripts from Java. Collectively I still refer to this as “the hard way,” though it isn’t terribly hard, but it’s awfully indirect compared to the easy way. From now on I’ll stop trying to maintain the artificial separation of Java code from Groovy code. In order to make progress all I need to do is put the Groovy code into a class.

3.2.4. Calling Groovy from Java the easy way

All the techniques I’ve discussed so far—using the JSR 223 ScriptEngine, or using the Groovy API classes Eval and GroovyShell—work just fine but feel overly complicated. Groovy is supposed to simplify your life, so although the mechanisms shown in the previous section all work, for most use cases there’s an easier way.

The easiest way to call Groovy from Java is to put the Groovy code in a class and compile it. Then Java code can instantiate the class and invoke its methods the normal way.

The Easy Way

To call Groovy from Java, put the Groovy code in a class, compile it as usual, and then instantiate it and invoke methods as though it was Java.

Let’s return, once again, to the geocoder. This time, however, I’ll refactor it into a class that can be instantiated, with methods that can be invoked from outside. The process is shown in figure 3.6.

Figure 3.6. Mixing Java and Groovy classes. The Java app instantiates a Location and supplies it with street, city, and state values. It sends the new Location to the Groovy geocoder, whose fillInLatLng method supplies the latitude and longitude, which can then be retrieved by Java again.

As the figure shows, the Java application will use a Location class to store all the needed attributes. It will supply the street, city, and state fields as input parameters, but the Location class will also include latitude and longitude fields that will be updated by the Groovy geocoder. The geocoder itself will be written in Groovy, because it’s easy to write the RESTful web service client code that way.[7]

7 Note this is just like the geocoder with the Stadium class used in chapter 2 when I discussed the Groovy Baseball application. The differences here are the CSV output and that I’m invoking the Groovy implementation from Java.

Here’s the new Location class, which could be written in either Java or Groovy. This time, to keep the code simple I’ll use a Groovy POGO:

class Location {
    String street
    String city
    String state

    double latitude
    double longitude
}

The Location class encapsulates the address information in strings and provides double variables for the latitude and longitude values that will be set using the geocoder. Speaking of the geocoder, the next listing shows a revised version that wraps the script into a class.

Listing 3.6. A Groovy class for geocoding
class Geocoder {
    def base = 'http://maps.google.com/maps/geo?'

    void fillInLatLong(Location loc) {
        def addressFields = loc.street ?
            [loc.street,loc.city,loc.state] : [loc.city,loc.state]
        def address = addressFields.collect {
            URLEncoder.encode(it,'UTF-8')
        }.join(',')
        def params = [q:address,sensor:false,
            output:'csv',key:'ABQIAAAAa...']
        def url = base + params.collect { k,v -> "$k=$v" }.join('&')
        def (code,level,lat,lng) = url.toURL().text.split(',')
        loc.latitude = lat.toDouble()
        loc.longitude = lng.toDouble()
    }
}

The fillInLatLong method takes a Location as an argument. Strictly speaking, I didn’t have to declare a type for the parameter at all. I could have relied on duck typing within the method and just been careful not to call it with anything other than an object with street, city, and state properties. Still, I’m building the service with a Location in mind, so it doesn’t hurt to say so.

The addressFields variable uses the ternary operator to determine whether or not a street has been supplied when returning the collection of address components. Note that I’m appealing to the so-called “Groovy truth” here, in that I don’t need to compare loc.street to null or an empty string explicitly. Any non-blank value of the street field as part of the loc argument will return true, so it will be added to the collection.

The rest of the class is the same as the previous script, though to make the class more useful I went to the trouble of converting the string results to doubles before returning the location.

One final issue is notable, and it highlights an important difference between a script and a class. All of the variables, whether they are local variables or attributes, have to be declared. There are no undefined variables, so there’s also no binding to worry about any more.

How do I use these classes (Geocoder and Location) from Java? Just instantiate them and call methods as usual. In the previous section I started accumulating JUnit 4 tests into a test class. Here’s another test to add to that set:

@Test
public void testGeocoder() {
    Location loc = new Location();
    loc.setState("1600 Pennsylvania Avenue");
    loc.setCity("Washington");
    loc.setState("DC");
    Geocoder geocoder = new Geocoder();
    geocoder.fillInLatLong(loc);
    assertEquals(38.895,loc.getLatitude(),0.001);
    assertEquals(-77.037,loc.getLongitude(),0.001);
}

It doesn’t get much easier than that. I don’t need to instantiate a script engine or worry about Groovy shells or class loaders. Just instantiate and populate a Location, instantiate a Geocoder, and invoke the desired method.

From now on all of the examples I show will do integration the easy way. Again, this isn’t a value judgment against all the techniques demonstrated earlier in the chapter. If you want to call an existing Groovy script from Java, or you’re required to keep Java and Groovy code separate in your application, the previous mechanisms all work. Freely intermixing classes the way this script does, however, is very easy.

One last issue remains before I start looking at how Groovy might help Java. So far in this chapter the goal was always to call Groovy from Java. What about the other direction? How do you call Java from Groovy?

3.2.5. Calling Java from Groovy

Actually, this is so easy it hardly deserves a section at all. I’ve already shown it more than once. Remember the earlier example using the Google V2 geocoder (reproduced here for convenience)?

The integration is already here through the use of the library class and various Java methods. I needed to pass the address to Google in URL-encoded form. To do that I ran each element of the address (street, city, and state) through the java.net.URL-Encoder, using its encode method. In other words, the Groovy script used a Java library class and called one of its methods.

Lessons learned (integration)

1.  Groovy scripts can be called with Java alone using the JSR 223 script engine.

2.  The Groovy Eval class makes calling scripts involving zero, one, two, or three arguments simple.

3.  The GroovyShell and Binding classes are used to programmatically set input variables, invoke a script, and retrieve its result.

4.  The easiest way to call Groovy from Java is to make a Groovy class, compile it, instantiate it in Java, and call the methods as usual.

The combination of Java and Groovy is also emphasized in Figure 3.3, shown with the original listing. In that figure each Java method and each Groovy method is indicated with arrows.

The fact that the script mixes both Java and Groovy is true of practically any Groovy script. Groovy rests on the foundation of the Java libraries. It enhances those libraries, as you’ll see in section 4.3 on the Groovy JDK, but there’s no need to re-invent the flat tire.[8] Groovy is perfectly happy to use any Java classes you supply, and it makes many of them better.

8 Re-inventing the flat tire is what happens when you try to re-invent the wheel and get it wrong.

Compile with groovyc

Whenever you mix Java and Groovy, compile everything with groovyc. Let groovyc handle all the cross-compiler issues.

In the next chapter I’ll look at some of the ways Groovy improves Java.

Don’t separate Groovy and Java classes

The natural tendency when using two different languages is to separate the two codebases and compile them independently. With Groovy and Java that can lead to all sorts of problems, especially when cyclic dependencies are involved (in other words, Java class A uses Groovy class B, which invokes another method from Java class A, and so on). Maven projects in particular lead you down this path, because their default layouts naturally suggest putting Java code under src/main/java and Groovy code under src/main/groovy. The idea then is to use javac to compile the Java code and groovyc to compile the Groovy code.

Although you probably can get that to work, it makes life much more difficult than it needs to be. The developers of Groovy have worked hard on the cross-compilation issue for years. It’s better for us, as users of both languages, to take advantage of their progress.

The simplest way to compile Groovy and Java in the same project is to let the groovyc compiler handle both codebases. Groovy knows all about Java and is quite capable of handling it. Any compiler flags you would normally send to javac work just fine in groovyc as well. This is actually a good general principle.

In the projects in this book I’ll let groovyc do all the work. I’ll show specific examples of this in chapter 5, but you can safely assume I’m using groovyc throughout.

3.3. Summary

This chapter is about basic Groovy / Java integration, regardless of use case. After reviewing all the different ways to call Groovy from Java, from the JSR-223 Script-Engine to the GroovyShell and Eval classes in Groovy, I switched to the easy way, which is to put Groovy in a class and use it like any other library class. This easy blend of Java and Groovy will be used from now on.

Next I reviewed many ways that Groovy can help Java at the basic level, from POJO enhancements to AST transformations to building XML and more. I’ll use these techniques in future chapters wherever they can help. I’ll also review other helpful techniques along the way, though these are most of the major ones.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.34.25