Grape is a JAR dependency manager embedded into Groovy. Grape lets you quickly add maven repository dependencies to yourclasspath, making scripting even easier. The simplest use is as simple as adding an annotation to your script:
@Grab(group='org.springframework', module='spring-orm', version='5.2.8.RELEASE')import org.springframework.jdbc.core.JdbcTemplate@Grab also supports a shorthand notation:
@Grab('org.springframework:spring-orm:5.2.8.RELEASE')import org.springframework.jdbc.core.JdbcTemplateNote that we are using an annotated import here, which is the recommended way. You can also search fordependencies onmvnrepository.com and it willprovide you the@Grab annotation form of thepom.xml entry.
Not all dependencies are in maven central. You can add new ones likethis:
@GrabResolver(name='restlet', root='http://maven.restlet.org/')@Grab(group='org.restlet', module='org.restlet', version='1.1.6')Some maven dependencies need classifiers in order to be able to resolve.You can fix that like this:
@Grab(group='net.sf.json-lib', module='json-lib', version='2.2.3', classifier='jdk15')Sometimes you will want to exclude transitive dependencies as you mightbe already using a slightly different but compatible version of someartifact. You can do this as follows:
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')@GrabExclude('xml-apis:xml-apis')Because of the way JDBC drivers are loaded, you’ll need to configureGrape to attach JDBC driver dependencies to the system class loader.I.e:
@GrabConfig(systemClassLoader=true)@Grab(group='mysql', module='mysql-connector-java', version='5.1.6')From groovysh use the method call variant:
groovy.grape.Grape.grab(group:'org.springframework', module:'spring', version:'2.5.6')If you are behind a firewall and/or need to use Groovy/Grape through aproxy server, you can specify those settings on the command like via thehttp.proxyHost andhttp.proxyPort system properties:
groovy -Dhttp.proxyHost=yourproxy -Dhttp.proxyPort=8080 yourscript.groovy
Or you can make this system-wide by adding these properties to yourJAVA_OPTS environment variable:
JAVA_OPTS = -Dhttp.proxyHost=yourproxy -Dhttp.proxyPort=8080
If you want to see what Grape is doing set the system propertygroovy.grape.report.downloads totrue (e.g. add-Dgroovy.grape.report.downloads=true to invocation or JAVA_OPTS) and Grape willprint the following infos to System.error:
Starting resolve of a dependency
Starting download of an artifact
Retrying download of an artifact
Download size and time for downloaded artifacts
To log with even more verbosity, increase the Ivy log level(defaults to-1). For example-Divy.message.logger.level=4.
Grape (TheGroovy Adaptable Packaging Engine orGroovy AdvancedPackaging Engine) is the infrastructure enabling the grab() calls inGroovy, a set of classes leveragingIvy to allow for a repository drivenmodule system for Groovy. This allows a developer to write a script withan essentially arbitrary library requirement, and ship just the script.Grape will, at runtime, download as needed and link the named librariesand all dependencies forming a transitive closure when the script is runfrom existing repositories such as Maven Central.
Grape follows the Ivy conventions for module version identification,with naming change.
group - Which module group the module comes from. Translatesdirectly to a Maven groupId or an Ivy Organization. Any group matching/groovy[x][\..*]^/ is reserved and may have special meaning to thegroovy endorsed modules.
module - The name of the module to load. Translated directly to aMaven artifactId or an Ivy artifact.
version - The version of the module to use. Either a literal version`1.1-RC3' or an Ivy Range `[2.2.1,)' meaning 2.2.1 or any greaterversion).
classifier - The optional classifier to use (for example,jdk15)
The downloaded modules will be stored according to Ivy’s standardmechanism with a cache root of~/.groovy/grapes
One or moregroovy.lang.Grab annotations can be added at any place thatannotations are accepted to tell the compiler that this code relies onthe specific library. This will have the effect of adding the library tothe classloader of the groovy compiler. This annotation is detected andevaluated before any other resolution of classes in the script, soimported classes can be properly resolved by a@Grab annotation.
import com.jidesoft.swing.JideSplitButton@Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,2.3.0)')public class TestClassAnnotation { public static String testMethod () { return JideSplitButton.class.name }}An appropriategrab(…) call will be added to the static initializerof the class of the containing class (or script class in the case of anannotated script element).
In early versions of Groovy, if you wanted to use a Grab annotation multiple timeson the same node you had to use the@Grapes annotation, e.g.:
@Grapes([ @Grab(group='commons-primitives', module='commons-primitives', version='1.0'), @Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7')])class Example {// ...}Otherwise you’d encounter the following error:
Cannot specify duplicate annotation on the same member
But in recent versions, @Grapes is purely optional.
Technical notes:
Originally, Groovy stored the Grab annotations for access at runtimeand duplicates aren’t allowed in the bytecode. In current versions, @Grab has onlySOURCE retention, so the multiple occurrences aren’t an issue.
Future versions of Grape may support using the Grapes annotation toprovide a level of structuring, e.g. allowing a GrabExclude or GrabResolverannotation to apply to only a subset of the Grab annotations.
Typically a call to grab will occur early in the script or in classinitialization. This is to ensure that the libraries are made availableto the ClassLoader before the groovy code relies on the code. A coupleof typical calls may appear as follows:
import groovy.grape.Grape// random maven libraryGrape.grab(group:'com.jidesoft', module:'jide-oss', version:'[2.2.0,)')Grape.grab([group:'org.apache.ivy', module:'ivy', version:'2.0.0-beta1', conf:['default', 'optional']], [group:'org.apache.ant', module:'ant', version:'1.7.0'])Multiple calls to grab in the same context with the same parametersshould be idempotent. However, if the same code is called with adifferentClassLoader context then resolution may be re-run.
If theargs map passed into thegrab call has an attributenoExceptions that evaluates true no exceptions will be thrown.
grab requires that aRootLoader orGroovyClassLoader be specified orbe in theClassLoader chain of the calling class. By default failure tohave such aClassLoader available will result in module resolution andan exception being thrown
The ClassLoader passed in via theclassLoader: argument and itsparent classloaders.
The ClassLoader of the object passed in as thereferenceObject:argument, and its parent classloaders.
The ClassLoader of the class issuing the call tograb
group: - <String> - Which module group the module comes from.Translates directly to a Maven groupId. Any group matching/groovy(|\..|x|x\..)/ is reserved and may have special meaning to thegroovy endorsed modules.
module: - <String> - The name of the module to load. Translateddirectly to a Maven artifactId.
version: - <String> and possibly <Range> - The version of the moduleto use. Either a literal version `1.1-RC3' or an Ivy Range `[2.2.1,)'meaning 2.2.1 or any greater version).
classifier: - <String> - The Maven classifier to resolve by.
conf: - <String>, defaultdefault' - The configuration or scope ofthe module to download. The default conf is `default: which maps to themavenruntime andmaster scopes.
force:- <boolean>, defaults true - Used to indicate that thisrevision must be used in case of conflicts, independently of
conflicts manager
changing: - <boolean>, default false - Whether the artifact canchange without its version designation changing.
transitive: - <boolean>, default true - Whether to resolve otherdependencies this module has or not.
There are two principal variants ofgrab, one with a single Map andone with an arguments Map and multiple dependencies map. A call to thesingle map grab is the same as calling grab with the same map passed intwice, so grab arguments and dependencies can be mixed in the same map,and grab can be called as a single method with named parameters.
There are synonyms for these parameters. Submitting more than one is aruntime exception.
group:,groupId:,organisation:,organization:,org:
module:,artifactId:,artifact:
version:,revision:,rev:
conf:,scope:,configuration:
classLoader: - <GroovyClassLoader> or <RootClassLoader> - TheClassLoader to add resolved Jars to
refObject: - <Object> - The closest parent ClassLoader for theobject’s class will be treated as though it were passed in asclassLoader:
validate: - <boolean>, default false - Should poms or ivy files bevalidated (true), or should we trust the cache (false).
noExceptions: - <boolean>, default false - If ClassLoader resolutionor repository querying fails, should we throw an exception (false) orfail silently (true).
Grape added a command line executable `grape' that allows for theinspection and management of the local grape cache.
grape install [-hv] <group> <module> [<version>] [<classifier>]
This installs the specified groovy module or maven artifact. If aversion is specified that specific version will be installed, otherwisethe most recent version will be used (as if `*' we passed in).
grape list
Lists locally installed modules (with their full maven name in the caseof groovy modules) and versions.
grape resolve [-adhisv] (<groupId> <artifactId> <version>)+
This returns the file locations of the jars representing the artifactsfor the specified module(s) and the respective transitive dependencies.You may optionally pass in -ant, -dos, or -shell to get the dependenciesexpressed in a format applicable for an ant script, windows batch file,or unix shell script respectively. -ivy may be passed to see thedependencies expressed in an ivy like format.
grape uninstall [-hv] <group> <module> <version>
This uninstalls a particular grape: it non-transitively removes therespective jar file from the grape cache.
If you need to change the directory grape uses for downloading librariesyou can specify the grape.root system property to change the default(which is ~/.groovy/grapes)
groovy -Dgrape.root=/repo/grapes yourscript.groovy
You can customize the ivy settings that Grape uses by creating a~/.groovy/grapeConfig.xml file. If no such file exists,hereare the default settings used by Grape.
For more information on how to customize these settings, please refer totheIvydocumentation.
Using Apache Commons Collections:
// create and use a primitive array list@Grab(group='commons-primitives', module='commons-primitives', version='1.0')import org.apache.commons.collections.primitives.ArrayIntListdef createEmptyInts() { new ArrayIntList() }def ints = createEmptyInts()ints.add(0, 42)assert ints.size() == 1assert ints.get(0) == 42Using TagSoup:
// find the PDF links of the Java specifications@Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2.1')def getHtml() { def parser = new XmlParser(new org.ccil.cowan.tagsoup.Parser()) parser.parse("https://docs.oracle.com/javase/specs/")}html.body.'**'.a.@href.grep(~/.*\.pdf/).each{ println it }Using Google Collections:
import com.google.common.collect.HashBiMap@Grab(group='com.google.code.google-collections', module='google-collect', version='snapshot-20080530')def getFruit() { [grape:'purple', lemon:'yellow', orange:'orange'] as HashBiMap }assert fruit.lemon == 'yellow'assert fruit.inverse().yellow == 'lemon'Launching a Jetty server to serve Groovy templates:
@Grab('org.eclipse.jetty.aggregate:jetty-server:8.1.19.v20160209')@Grab('org.eclipse.jetty.aggregate:jetty-servlet:8.1.19.v20160209')@Grab('javax.servlet:javax.servlet-api:3.0.1')import org.eclipse.jetty.server.Serverimport org.eclipse.jetty.servlet.ServletContextHandlerimport groovy.servlet.TemplateServletdef runServer(duration) { def server = new Server(8080) def context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS) context.resourceBase = "." context.addServlet(TemplateServlet, "*.gsp") server.start() sleep duration server.stop()}runServer(10000)Grape will download Jetty and its dependencies on first launch of thisscript, and cache them. We create a new Jetty Server on port 8080,then expose Groovy’s TemplateServlet at the root of the context — Groovycomes with its own powerful template engine mechanism. We start theserver and let it run for a certain duration. Each time someone will hithttp://localhost:8080/somepage.gsp, it will display the somepage.gsptemplate to the user — those template pages should be situated in thesame directory as this server script.