Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Andrey Adamovich - Groovy 2 Cookbook - 2013.pdf
Скачиваний:
44
Добавлен:
19.03.2016
Размер:
26.28 Mб
Скачать

Chapter 2

The previous code snippet adds two lines of William Shakespeare's poem at the end of the poem.txt file, and then it prints the file contents on the console. Even though we operate solely on the java.io.File object, we call methods that did not originally exist in the JDK. Additional utility methods that appear on standard classes are described in the Groovy JDK documentation located at http://groovy.codehaus.org/groovy-jdk/. Those methods can be called due to Groovy's metaclass functionality, which is discussed in more detail in Chapter 9, Metaprogramming and DSLs in Groovy, which allows to add your own methods to any Java class used within Groovy code.

See also

ff Chapter 4, Working with Files in Groovy

ff Chapter 9, Metaprogramming and DSLs in Groovy ff http://groovy.codehaus.org/groovy-jdk/

Embedding Groovy into Java

There are plenty of scripting languages available at the moment on the JVM. Some of them only offer expression language support for data binding and configuration needs, for

example, MVEL (http://mvel.codehaus.org/) and SpEL (Spring Expression Language, http://www.springsource.org/documentation). Others provide a fully featured programming language. Examples of these are JRuby, Jython, Clojure, Jaskell, and

of course, Groovy.

In this recipe, we will show you how to benefit from Groovy scripting from within your

Java application.

Getting ready

To embed Groovy scripts into your Java code base, first of all, you need to add groovy-all- 2.x.x.jar library to your class path. Or if you are using Java 7 and want to take advantage of the invokedynamic optimization, you should add groovy-all-2.x.x-indy.jar instead (see also the Running Groovy with invokedynamic support recipe in Chapter 1, Getting Started with Groovy).

These libraries are located inside the Groovy distribution archive under the embeddable folder. Another way to get those JAR files is from Maven Central Repository at

http://search.maven.org/.

51

www.it-ebooks.info

Using Groovy Ecosystem

The groovy-all artifact contains all the required classes to run Groovy code. It also includes dependencies such as Antlr, ASM, and Apache Commons inside the archive to be able to

run Groovy with only single JAR on the class path. However, you shouldn't worry about class version conflicts if you use one of these libraries because all foreign classes are placed under special packages inside the groovy-all library.

How to do it...

There are several ways in which a Groovy script can be invoked from your Java application, but the recommended one—and also the simplest—is using the GroovyShell class.

1.Let's start by creating a new Java class named CallGroovyUsingGroovyShell that has the following content:

import groovy.lang.GroovyShell; import groovy.lang.Script; import java.io.File;

import java.io.IOException;

import org.codehaus.groovy.control.CompilationFailedException; public class CallGroovyUsingGroovyShell {

public static void main(String[] args) throws CompilationFailedException,

IOException {

// Create shell object.

GroovyShell shell = new GroovyShell(); double result = (Double) shell.

evaluate("(4/3) * Math.PI * 6370 " +

"// Earth volume in cubic killometeres "); System.out.println(result);

}

}

The class instantiates a GroovyShell object and calls the evaluate method of the object by passing a String containing Groovy code.

2.Let's explore more methods of the GrovyShell class by adding the following Java code to the main method:

shell.evaluate("name = 'Andrew'"); shell.setVariable("name", "Andrew"); shell.evaluate("println \"My name is ${name}\""); shell.evaluate("name = name.toUpperCase()"); System.out.println(shell.getVariable("name")); System.out.println(shell.getProperty("name")); shell.evaluate("println 'Hello from shell!'"); System.out.println(shell.evaluate(" 1 + 2 "));

52

www.it-ebooks.info

Chapter 2

3.In the same folder where the newly created Java class is located, place a Groovy script named script.groovy, with the following content:

def scriptName = 'external script' name = scriptName

println "Hello from ${name} on ${currentDate}!"

def getCurrentDate() {

new Date().format('yyyy-MM-dd')

}

4.Let's continue by adding a new line to the main method of our Java class: shell.evaluate(new File("script.groovy"));

5.Now compile and run the class. The groovy-all-2.x.x.jar library must be located in the same folder as the Java and the Groovy file.

On Linux/OS X:

javac -cp groovy-all-2.1.6.jar CallGroovyUsingGroovyShell.java

java -cp .:groovy-all-2.1.6.jar CallGroovyUsingGroovyShell

On Windows:

javac -cp groovy-all-2.1.6.jar CallGroovyUsingGroovyShell.java

java -cp .;groovy-all-2.1.6.jar CallGroovyUsingGroovyShell

The output should look as follows:

6682.593603822243 My name is Andrew My name is Andrew ANDREW

ANDREW

Hello from shell! 3

Hello from external script on 2013-08-31!

6.Let's add more examples to the CallGroovyUsingGroovyShell class. Append the following lines to the main method of the class:

Script script = shell.parse(new File("script.groovy")); script.run();

System.out.println(script.

invokeMethod("getCurrentDate", null)); System.out.println(script.getProperty("name"));

// Calling internal script

53

www.it-ebooks.info

Using Groovy Ecosystem

script = shell.

parse("println 'Hello from internal script!'"); script.run();

script = shell.parse(new File("functions.groovy")); System.out.println(script.invokeMethod("year", null));

7.Add one more Groovy file to the list of files for this recipe, namedfunctions.groovy:

def year() { Calendar.instance.get(Calendar.YEAR)

}

def month() { Calendar.instance.get(Calendar.MONTH)

}

def day() { Calendar.instance.get(Calendar.DAY_OF_MONTH)

}

8.Compile and run again; the additional output should look as follows:

Hello from external script on 2013-08-31! 2013-08-31

external script

Hello from internal script! 2013

How it works...

In the Java class example, the GroovyShell object is instantiated using the default constructor.

In step 1, the Groovy code passed to the evaluate method calculates the result of the simple arithmetical expression. No return statement is used, but still the expression evaluates correctly. The reason is that in Groovy, the return statement is optional, and an expression will always return the value of the last statement. The mathematical expression's result type is java.lang.Double as we only operate with floating numbers; this is why we can safely cast it.

Furthermore, the expression refers to a constant defined in the java.lang.Math class, without explicitly importing it. This is possible due to the fact that Groovy imports all java.lang.* classes automatically, just like Java.

There is also a comment at the end of the expression, which is safely ignored. Similar to Java, comments can appear anywhere in Groovy code.

54

www.it-ebooks.info

Chapter 2

The GroovyShell object supports defining global variables, which can be re-used by evaluated scripts, by using the setVariable method, as displayed in step 2.

The variable name is set and then used inside a script evaluated later. The variable will be available to all the scripts executed throughout the lifetime of the GroovyShell object.

The variable's value can also be changed during script execution and retrieved later using the getVariable method.

In step 3, we can observe another useful feature of the integration of Groovy with Java; the possibility of executing external Groovy scripts from Java by passing a java.io.File object to the evaluate method.

You can also create individual Script objects for repeated executions:

Script script = shell.parse(new File("HelloWorld2.groovy")); script.run(); // run first time

script.run(); // run second time

In this case, the script code will be compiled by the parse method and the script execution will be faster than if we do repeated calls of the evaluate method.

Steps 6 and 7 show how you can also execute individual methods if they are defined by the code located in an external script. Once the script is successfully compiled, the invokeMethod can be used to call any function declared in the external script.

There's more...

If you are familiar with JSR-223, which provides the specification for the Java SE scripting API, you can also use it with Groovy. JSR-223 is recommended over the GroovyShell approach if you want to be able to switch to a different scripting language at any point. The next example shows how to get started with the scripting API:

import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException;

public class CallGroovyUsingJSR223 {

public static void main(String[] args) throws ScriptException {

ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("groovy");

55

www.it-ebooks.info

Using Groovy Ecosystem

//Expression evalution. System.out

.println(engine

.eval("(4/3) * Math.PI * 6370 " +

"// Earth volume in cubic killometeres "));

//Variable binding.

engine.put("name", "Andrew"); engine.eval("println \"My name is ${name}\"");

}

}

The key to start using Groovy with JSR-233 is again to add the groovy-all artifact to the classpath. Adding the jar will automatically bind the Groovy script engine into JVM, which can be retrieved by a call to manager.getEngineByName("groovy") as shown in the previous example. Please note that the JSR-233 specification is only available from Java 6.

Another way to dynamically embed Groovy into Java code is by defining the Groovy classes and parsing them with GroovyClassLoader. For example, let's assume we have the following

TimePrinter.groovy file:

class TimePrinter implements Runnable { void run() {

(1..10).each {

println Calendar.instance.time Thread.sleep(1000)

}

}

}

As you can see, it defines the TimePrinter class, which implements the Runnable interface. The method run prints the current time and then sleeps for one second, and it repeats that operation 10 times. This code also shows one way of looping in Groovy: the (1..10) expression under the hood creates an object of type groovy.lang.IntRange. This class implements the java.lang.Iterable interface, which in Groovy has an extension method called each. This takes a code block (groovy.lang.Closure) as an input parameter and executes it for every element of java.lang.Iterable. For more information about Groovy Ranges, please refer to

http://groovy.codehaus.org/api/groovy/lang/Range.html.

In order to use the TimePrinter class dynamically at runtime, we need to create an instance of GroovyClassLoader and call the parseClass method on it in order to get the new class definition:

// Create class loader.

GroovyClassLoader gcl = new GroovyClassLoader();

// Parse and load class.

56

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]