Make groovy script grab a jar off the filesystem like grape

Robert Kleemann picture Robert Kleemann · May 14, 2011 · Viewed 9.9k times · Source

Grape seems to work fairly well for adding jars to your classpath. It also does a lot of other things such as fetching and dependency management. e.g.

#!/home/robert/bin/groovy

import org.apache.commons.lang.StringUtils

@Grab(group='commons-lang', module='commons-lang', version='2.4')

def strings = ['Hello', 'Groovy', 'AVeryLongWord!', 'A simple sentence']
strings.each { String aString ->
    println "$aString: ${StringUtils.abbreviate(aString,10)}"
}

Unfortunately if there is a jar on my filesystem that I want to dynamically add to the filesystem then I have to resort to a much uglier solution.

#!/home/robert/bin/groovy

def loader = this.class.classLoader.rootLoader
loader.addURL(new File("/home/robert/somejars/arithmetic-1.1.jar").toURI().toURL())

// can't use traditional package import
arithmeticMainClass = Class.forName("org.scharp.arithmetic.Main")

println "42 - 23 = " + arithmeticMainClass.subtract(42, 23)

// can't use "new" operator
myArithmeticObject = arithmeticMainClass.newInstance()

Is there a way to make grape grab a jar from the filesystem? If not, can I somehow replicate what grape is doing in groovy/java?

I would like this solution to work for scripts that can be run by many users and many incompatible jars so adding jars to a common directory such as ~/.groovy/lib/ won't work.

I could create a local maven repository for local, jar libaries but that seems like overkill.

Answer

ericksn picture ericksn · Nov 5, 2013

This is how I solved this. When Grape (Ivy) wants something it caches it under the ~/.groovy/grapes directory. All you need to do is just create your own ivy.xml file and throw your jar in there. I figured it out by just looking at some of the other artifacts donwloaded from maven. Here is a small example.....

We use Oracle here and I wanted it's jdbc jar file to be able to be 'Grabbed' by my Groovy scripts. Unfortunately, I could not find any repository that had this jar on the web.

  • Step 1 : create directory ~/.groovy/grapes/com.oracle
  • Step 2 : create directory ~/.groovy/grapes/com.oracle/ojdbc6
  • Step 3 : create directory ~/.groovy/grapes/com.oracle/ojdbc6/jars
  • Step 4 : Get a copy of Oracle's ojdbc jar file and rename it. Our oracle version is 11.2.0.1.0 and we use Java6 so I got the locally installed ojdbc6.jar file and copied as ojdbc6-11.2.0.1.0.jar. This file I put into the directory created in the prior step.
  • Step 5 : create an ivy-11.2.0.1.0.xml config file.This file should be put into the directory created in step 2. For this step I heavily relied on examples from other artifacts grabbed. Any apache commons lib is a good example.

Here is my xml.

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven"
>
  <info organisation="com.oracle" module="ojdbc6" revision="11.2.0.1.0" status="release" publication="20130102153401">
    <license name="" />
    <description homepage="">Oracle ojdbc driver</description>
  </info>
  <configurations>
    <conf name="default" visibility="public" description="" extends="runtime,master" />
    <conf name="master" visibility="public" description="" />
    <conf name="compile" visibility="public" description="" />
    <conf name="provided" visibility="public" description="" />
    <conf name="runtime" visibility="public" description="" extends="compile" />
    <conf name="test" visibility="public" description="" extends="runtime" />
    <conf name="system" visibility="public" description="" />
    <conf name="sources" visibility="public" description="" />
    <conf name="javadoc" visibility="public" description="" />
    <conf name="optional" visibility="public" description="" />
  </configurations>
  <publications>
    <artifact name="ojdbc6" type="jar" ext="jar" conf="master" />
  </publications>
</ivy-module>

Now I can use this jar in my groovy scripts with the following....

@Grapes([
  @GrabConfig(systemClassLoader=true),
  @Grab('com.oracle:ojdbc6:11.2.0.1.0'),
])
import groovy.sql.*


To make things easy for deploying this grape to multiple servers I created a zip file that I could extract anywhere....

$ unzip -qql oracle_jdbc_groovy_grape.zip
        0  06-11-2012 13:50   .groovy/grapes/com.oracle/
        0  06-12-2012 14:17   .groovy/grapes/com.oracle/ojdbc6/
        0  06-12-2012 14:17   .groovy/grapes/com.oracle/ojdbc6/jars/
  2111220  06-11-2012 11:46   .groovy/grapes/com.oracle/ojdbc6/jars/ojdbc6-11.2.0.1.0.jar
     2349  06-11-2012 11:50   .groovy/grapes/com.oracle/ojdbc6/ivy-11.2.0.1.0.xml