Apache Groovy is a powerful multi-faceted programming language for the JVM platform
—
Grape dependency management system for dynamic dependency resolution and loading, including @Grab annotation support for declaring dependencies in scripts. This system allows Groovy scripts to automatically download and use external libraries at runtime.
Main API for programmatic dependency management.
class Grape {
/**
* Grabs a dependency using string notation.
*/
static void grab(String endorsedModule);
/**
* Grabs a dependency using map notation.
*/
static void grab(Map<String, Object> dependency);
/**
* Grabs multiple dependencies.
*/
static void grab(Map<String, Object>... dependencies);
/**
* Grabs dependencies with custom class loader.
*/
static void grab(ClassLoader loader, Map<String, Object>... dependencies);
/**
* Adds a repository resolver.
*/
static void addResolver(Map<String, Object> args);
/**
* Resolves dependencies to URIs without loading.
*/
static URI[] resolve(Map<String, Object> args);
/**
* Resolves dependencies to URIs with custom settings.
*/
static URI[] resolve(Map<String, Object> args, URI... uris);
/**
* Lists available dependencies in the grape cache.
*/
static Map<String, Map<String, List<String>>> enumerateGrapes();
/**
* Gets the instance of the grape engine.
*/
static GrapeEngine getInstance();
/**
* Sets the instance of the grape engine.
*/
static void setInstance(GrapeEngine engine);
}Interface for custom grape implementations.
interface GrapeEngine {
/**
* Grabs a dependency.
*/
void grab(Map<String, Object> dependency);
/**
* Grabs dependencies with custom class loader.
*/
void grab(ClassLoader loader, Map<String, Object> dependency);
/**
* Adds a repository resolver.
*/
void addResolver(Map<String, Object> args);
/**
* Resolves dependencies to URIs.
*/
URI[] resolve(Map<String, Object> args);
/**
* Resolves dependencies with custom URIs.
*/
URI[] resolve(Map<String, Object> args, URI... uris);
/**
* Lists available dependencies.
*/
Map<String, Map<String, List<String>>> enumerateGrapes();
}Annotations for declarative dependency management in scripts.
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
@interface Grab {
/**
* The group ID of the dependency.
*/
String group() default "";
/**
* The module/artifact ID of the dependency.
*/
String module();
/**
* The version of the dependency.
*/
String version();
/**
* The classifier of the dependency.
*/
String classifier() default "";
/**
* The extension/type of the dependency.
*/
String ext() default "";
/**
* The configuration to use.
*/
String conf() default "";
/**
* Whether to force the version.
*/
boolean force() default false;
/**
* Whether to include transitive dependencies.
*/
boolean transitive() default true;
/**
* Whether to change the class loader.
*/
boolean changing() default false;
/**
* Modules to exclude from transitive dependencies.
*/
GrabExclude[] excludes() default {};
}
@Target({})
@Retention(RetentionPolicy.SOURCE)
@interface GrabExclude {
/**
* The group ID to exclude.
*/
String group() default "";
/**
* The module ID to exclude.
*/
String module() default "";
}
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
@interface Grapes {
/**
* Array of @Grab annotations.
*/
Grab[] value();
}
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
@interface GrabResolver {
/**
* The name of the repository.
*/
String name() default "";
/**
* The root URL of the repository.
*/
String root() default "";
/**
* Whether to use M2 compatible layout.
*/
boolean m2Compatible() default true;
}
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
@interface GrabConfig {
/**
* System properties to set.
*/
String[] systemProperties() default {};
/**
* Whether to validate signatures.
*/
boolean disableChecksums() default false;
/**
* Whether to auto download sources.
*/
boolean autoDownload() default true;
}AST transformations that process Grab annotations.
class GrabAnnotationTransformation implements ASTTransformation {
/**
* Processes @Grab annotations during compilation.
*/
void visit(ASTNode[] nodes, SourceUnit source);
/**
* Extracts grab information from annotations.
*/
Map<String, Object> extractGrabInfo(AnnotationNode annotation);
/**
* Resolves and loads dependencies.
*/
void processGrabs(List<Map<String, Object>> grabs, ClassLoader loader);
}
class GrabResolverTransformation implements ASTTransformation {
/**
* Processes @GrabResolver annotations during compilation.
*/
void visit(ASTNode[] nodes, SourceUnit source);
}import groovy.grape.Grape;
// Grab a dependency programmatically using map notation
Map<String, Object> dependency = new HashMap<>();
dependency.put("group", "commons-lang");
dependency.put("module", "commons-lang");
dependency.put("version", "2.6");
Grape.grab(dependency);
// Now use the grabbed library
// This would work in a Groovy script context
// import org.apache.commons.lang.StringUtils;
// System.out.println(StringUtils.capitalize("hello world"));
// Grab using string notation (Groovy style)
// Grape.grab("commons-lang:commons-lang:2.6");
// Grab multiple dependencies at once
Map<String, Object> httpClient = new HashMap<>();
httpClient.put("group", "org.apache.httpcomponents");
httpClient.put("module", "httpclient");
httpClient.put("version", "4.5.13");
Map<String, Object> gson = new HashMap<>();
gson.put("group", "com.google.code.gson");
gson.put("module", "gson");
gson.put("version", "2.8.9");
Grape.grab(httpClient, gson);// In a Groovy script (.groovy file):
@Grab('commons-lang:commons-lang:2.6')
@Grab('com.google.code.gson:gson:2.8.9')
import org.apache.commons.lang.StringUtils
import com.google.gson.Gson
// Multiple grabs can be combined
@Grapes([
@Grab('org.apache.httpcomponents:httpclient:4.5.13'),
@Grab('org.apache.commons:commons-csv:1.9.0')
])
import org.apache.http.client.HttpClient
import org.apache.commons.csv.CSVFormat
// Script code using the grabbed dependencies
String text = "hello world"
String capitalized = StringUtils.capitalize(text)
println capitalized
Gson gson = new Gson()
String json = gson.toJson([name: "John", age: 30])
println jsonimport groovy.grape.Grape;
import java.util.Map;
import java.util.HashMap;
// Grab with exclusions
Map<String, Object> springDep = new HashMap<>();
springDep.put("group", "org.springframework");
springDep.put("module", "spring-context");
springDep.put("version", "5.3.21");
springDep.put("transitive", true);
// Add exclusions for transitive dependencies
Map<String, Object> exclude1 = new HashMap<>();
exclude1.put("group", "commons-logging");
exclude1.put("module", "commons-logging");
springDep.put("excludes", new Map[]{exclude1});
Grape.grab(springDep);
// Grab with specific classifier
Map<String, Object> sourceDep = new HashMap<>();
sourceDep.put("group", "org.apache.commons");
sourceDep.put("module", "commons-lang3");
sourceDep.put("version", "3.12.0");
sourceDep.put("classifier", "sources");
Grape.grab(sourceDep);
// Force a specific version
Map<String, Object> forcedDep = new HashMap<>();
forcedDep.put("group", "junit");
forcedDep.put("module", "junit");
forcedDep.put("version", "4.13.2");
forcedDep.put("force", true);
Grape.grab(forcedDep);import groovy.grape.Grape;
// Add a custom Maven repository
Map<String, Object> customRepo = new HashMap<>();
customRepo.put("name", "spring-milestone");
customRepo.put("root", "https://repo.spring.io/milestone");
customRepo.put("m2Compatible", true);
Grape.addResolver(customRepo);
// Add a custom Ivy repository
Map<String, Object> ivyRepo = new HashMap<>();
ivyRepo.put("name", "my-ivy-repo");
ivyRepo.put("root", "http://my-company.com/ivy-repo");
ivyRepo.put("m2Compatible", false);
Grape.addResolver(ivyRepo);
// Now grab dependencies from custom repositories
Map<String, Object> springDep = new HashMap<>();
springDep.put("group", "org.springframework");
springDep.put("module", "spring-core");
springDep.put("version", "6.0.0-M5");
Grape.grab(springDep);// In a Groovy script:
@GrabResolver(name='spring-milestones', root='https://repo.spring.io/milestone')
@GrabResolver(name='jcenter', root='https://jcenter.bintray.com/')
@Grab('org.springframework:spring-context:5.3.21')
@Grab(group='org.apache.commons', module='commons-lang3', version='3.12.0')
import org.springframework.context.ApplicationContext
import org.apache.commons.lang3.StringUtils
// Use the grabbed dependencies
println StringUtils.isBlank("") // true
println StringUtils.capitalize("hello") // Helloimport groovy.grape.Grape;
import java.net.URI;
// Resolve dependencies to get their file locations without loading
Map<String, Object> resolveArgs = new HashMap<>();
resolveArgs.put("group", "commons-lang");
resolveArgs.put("module", "commons-lang");
resolveArgs.put("version", "2.6");
URI[] resolvedUris = Grape.resolve(resolveArgs);
System.out.println("Resolved dependencies:");
for (URI uri : resolvedUris) {
System.out.println(" " + uri.toString());
}
// Resolve with multiple dependencies
Map<String, Object> dep1 = new HashMap<>();
dep1.put("group", "org.apache.commons");
dep1.put("module", "commons-csv");
dep1.put("version", "1.9.0");
Map<String, Object> dep2 = new HashMap<>();
dep2.put("group", "com.fasterxml.jackson.core");
dep2.put("module", "jackson-core");
dep2.put("version", "2.13.3");
Map<String, Object> resolveMultiple = new HashMap<>();
resolveMultiple.put("dependencies", new Map[]{dep1, dep2});
URI[] multipleUris = Grape.resolve(resolveMultiple);
System.out.println("Multiple resolved dependencies: " + multipleUris.length);import groovy.grape.Grape;
import java.util.Map;
// List all grapes in the cache
Map<String, Map<String, List<String>>> grapeCache = Grape.enumerateGrapes();
System.out.println("Grapes in cache:");
for (Map.Entry<String, Map<String, List<String>>> groupEntry : grapeCache.entrySet()) {
String group = groupEntry.getKey();
System.out.println("Group: " + group);
Map<String, List<String>> modules = groupEntry.getValue();
for (Map.Entry<String, List<String>> moduleEntry : modules.entrySet()) {
String module = moduleEntry.getKey();
List<String> versions = moduleEntry.getValue();
System.out.println(" Module: " + module);
System.out.println(" Versions: " + versions);
}
}import groovy.grape.Grape;
try {
// Attempt to grab a dependency that might not exist
Map<String, Object> badDep = new HashMap<>();
badDep.put("group", "com.nonexistent");
badDep.put("module", "fake-library");
badDep.put("version", "1.0.0");
Grape.grab(badDep);
} catch (Exception e) {
System.err.println("Failed to grab dependency: " + e.getMessage());
e.printStackTrace();
}
// Set system properties for debugging
System.setProperty("groovy.grape.report.downloads", "true");
System.setProperty("ivy.message.logger.level", "3"); // Verbose logging
// Grab with debugging enabled
Map<String, Object> debugDep = new HashMap<>();
debugDep.put("group", "org.slf4j");
debugDep.put("module", "slf4j-simple");
debugDep.put("version", "1.7.36");
Grape.grab(debugDep);// Example of programmatic grape usage in a build script context
import groovy.grape.Grape;
// Configure grape for build environment
Map<String, Object> mavenCentral = new HashMap<>();
mavenCentral.put("name", "central");
mavenCentral.put("root", "https://repo1.maven.org/maven2/");
mavenCentral.put("m2Compatible", true);
Grape.addResolver(mavenCentral);
// Grab build-time dependencies
Map<String, Object> antDep = new HashMap<>();
antDep.put("group", "org.apache.ant");
antDep.put("module", "ant");
antDep.put("version", "1.10.12");
antDep.put("transitive", false);
Grape.grab(antDep);
// Now use Ant tasks programmatically
// This would be in a Groovy context where you could import and use Antimport groovy.grape.Grape;
import groovy.lang.GroovyClassLoader;
// Create a custom class loader
GroovyClassLoader classLoader = new GroovyClassLoader();
// Grab dependencies into the custom class loader
Map<String, Object> commonsIo = new HashMap<>();
commonsIo.put("group", "commons-io");
commonsIo.put("module", "commons-io");
commonsIo.put("version", "2.11.0");
Grape.grab(classLoader, commonsIo);
// Now classes from commons-io should be available in the classLoader
// This enables isolation of dependencies per class loader
try {
Class<?> fileUtilsClass = classLoader.loadClass("org.apache.commons.io.FileUtils");
System.out.println("Successfully loaded: " + fileUtilsClass.getName());
// You could now use reflection to call methods on this class
// or compile and execute Groovy code that uses it
} catch (ClassNotFoundException e) {
System.err.println("Failed to load class: " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy