Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax.
—
Enhanced collection operations, builder patterns, configuration management, and utility classes that extend Java's standard library with Groovy-specific enhancements.
Create and manipulate objects dynamically at runtime.
/**
* Dynamic object that allows adding properties and methods at runtime
*/
class Expando extends GroovyObjectSupport {
/** Create empty Expando */
Expando()
/** Create Expando with initial properties */
Expando(Map properties)
/** Get property value dynamically */
Object getProperty(String name)
/** Set property value dynamically */
void setProperty(String name, Object value)
}Usage Examples:
// Create dynamic object
def person = new Expando()
person.name = "Alice"
person.age = 30
person.greet = { "Hello, I'm ${name}" }
println person.name // "Alice"
println person.greet() // "Hello, I'm Alice"
// Create with initial properties
def car = new Expando([
make: "Toyota",
model: "Camry",
year: 2020,
start: { "Starting ${make} ${model}" }
])
println car.start() // "Starting Toyota Camry"
// Add methods dynamically
person.celebrate = { years ->
age += years
return "Now I'm ${age} years old!"
}
println person.celebrate(1) // "Now I'm 31 years old!"Base classes for implementing various builder patterns.
/**
* Base class for implementing builder patterns
*/
abstract class BuilderSupport {
/** Create node with name only */
protected abstract Object createNode(Object name)
/** Create node with name and value */
protected abstract Object createNode(Object name, Object value)
/** Create node with name and attributes */
protected abstract Object createNode(Object name, Map attributes)
/** Create node with name, attributes, and value */
protected abstract Object createNode(Object name, Map attributes, Object value)
/** Set parent-child relationship */
protected void setParent(Object parent, Object child)
/** Get current node */
protected Object getCurrent()
/** Set current node */
protected void setCurrent(Object current)
}
/**
* Builder implementation using factory pattern
*/
class FactoryBuilderSupport extends BuilderSupport {
/** Register factory for node type */
void registerFactory(String name, Factory factory)
/** Register factory with alias */
void registerFactory(String name, String groupName, Factory factory)
/** Register bean factory */
void registerBeanFactory(String name, Class beanClass)
}Usage Examples:
// Custom builder implementation
class TreeBuilder extends BuilderSupport {
private Stack nodeStack = new Stack()
protected Object createNode(Object name) {
return createNode(name, null, null)
}
protected Object createNode(Object name, Object value) {
return createNode(name, null, value)
}
protected Object createNode(Object name, Map attributes) {
return createNode(name, attributes, null)
}
protected Object createNode(Object name, Map attributes, Object value) {
def node = [name: name, attributes: attributes ?: [:], value: value, children: []]
if (!nodeStack.empty()) {
nodeStack.peek().children << node
}
return node
}
protected void setParent(Object parent, Object child) {
// Handled in createNode
}
}
// Using the custom builder
def builder = new TreeBuilder()
def tree = builder.root {
branch(type: 'main') {
leaf('Leaf 1')
leaf('Leaf 2', color: 'green')
}
branch(type: 'secondary') {
leaf('Leaf 3')
}
}Tree structure representation and manipulation for XML-like data.
/**
* Represents a node in a tree structure (used by XML processing)
*/
class Node {
/** Create node with name */
Node(Object name)
/** Create node with name and value */
Node(Object name, Object value)
/** Create node with name and attributes */
Node(Object name, Map attributes)
/** Create node with parent, name, and value */
Node(Node parent, Object name, Object value)
/** Get node name */
Object name()
/** Get node value */
Object value()
/** Set node value */
void setValue(Object value)
/** Get node attributes */
Map attributes()
/** Get child nodes */
List children()
/** Get parent node */
Node parent()
/** Append child node with name */
Node appendNode(Object name)
/** Append child node with name and value */
Node appendNode(Object name, Object value)
/** Append child node with name and attributes */
Node appendNode(Object name, Map attributes)
/** Remove child node */
boolean remove(Node child)
/** Get attribute value */
Object attribute(Object key)
/** Get text content */
String text()
/** Find all nodes matching closure */
List findAll(Closure closure)
/** Find first node matching closure */
Node find(Closure closure)
}
/**
* List of Node objects with additional query capabilities
*/
class NodeList extends ArrayList<Node> {
/** Get nodes by name */
NodeList getAt(String name)
/** Get text content of all nodes */
String text()
/** Find all nodes matching closure */
NodeList findAll(Closure closure)
/** Get attribute values */
List getAttribute(String name)
}Hierarchical configuration objects with nested property support.
/**
* Configuration object supporting hierarchical properties
*/
class ConfigObject implements Map<String, Object> {
/** Create empty ConfigObject */
ConfigObject()
/** Check if config is empty */
boolean isEmpty()
/** Get property using dot notation */
Object getProperty(String name)
/** Set property using dot notation */
void setProperty(String name, Object value)
/** Merge with another ConfigObject */
ConfigObject merge(ConfigObject other)
/** Convert to Properties */
Properties toProperties()
/** Convert to Properties with prefix */
Properties toProperties(String prefix)
/** Flatten to Map */
Map flatten()
/** Flatten with custom separator */
Map flatten(String separator)
}Usage Examples:
// Create configuration
def config = new ConfigObject()
config.database.url = "jdbc:mysql://localhost:3306/mydb"
config.database.username = "user"
config.database.password = "pass"
config.server.port = 8080
config.server.host = "localhost"
// Access nested properties
println config.database.url // "jdbc:mysql://localhost:3306/mydb"
println config.server.port // 8080
// Map-style access
println config['database']['username'] // "user"
// Convert to Properties
def props = config.toProperties()
props.each { key, value ->
println "$key = $value"
}
// Merge configurations
def defaultConfig = new ConfigObject()
defaultConfig.server.timeout = 30
defaultConfig.server.retries = 3
def finalConfig = defaultConfig.merge(config)
println finalConfig.server.timeout // 30
println finalConfig.server.port // 8080Collections that fire events when modified.
/**
* List implementation that fires events on changes
*/
class ObservableList<E> extends ArrayList<E> {
/** Add property change listener */
void addPropertyChangeListener(PropertyChangeListener listener)
/** Remove property change listener */
void removePropertyChangeListener(PropertyChangeListener listener)
/** Add property change listener for specific property */
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
/** Remove property change listener for specific property */
void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
/** Get all property change listeners */
PropertyChangeListener[] getPropertyChangeListeners()
/** Fire property change event */
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue)
}
/**
* Map implementation that fires events on changes
*/
class ObservableMap<K, V> extends HashMap<K, V> {
/** Add property change listener */
void addPropertyChangeListener(PropertyChangeListener listener)
/** Remove property change listener */
void removePropertyChangeListener(PropertyChangeListener listener)
/** Add property change listener for specific property */
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
/** Get all property change listeners */
PropertyChangeListener[] getPropertyChangeListeners()
}
/**
* Set implementation that fires events on changes
*/
class ObservableSet<E> extends HashSet<E> {
/** Add property change listener */
void addPropertyChangeListener(PropertyChangeListener listener)
/** Remove property change listener */
void removePropertyChangeListener(PropertyChangeListener listener)
/** Get all property change listeners */
PropertyChangeListener[] getPropertyChangeListeners()
}Usage Examples:
import java.beans.PropertyChangeListener
// Observable list
def list = new ObservableList()
list.addPropertyChangeListener { event ->
println "List changed: ${event.propertyName} from ${event.oldValue} to ${event.newValue}"
}
list.add("item1") // Fires event
list.add("item2") // Fires event
list.remove("item1") // Fires event
// Observable map
def map = new ObservableMap()
map.addPropertyChangeListener("key1") { event ->
println "Key1 changed from ${event.oldValue} to ${event.newValue}"
}
map.put("key1", "value1") // Fires event for key1
map.put("key2", "value2") // No event (no listener for key2)
map.put("key1", "newvalue") // Fires event for key1Various utility classes for common operations.
/**
* PrintWriter that automatically handles indentation
*/
class IndentPrinter extends PrintWriter {
/** Create with Writer and indent string */
IndentPrinter(Writer writer, String indent)
/** Create with Writer, default indent */
IndentPrinter(Writer writer)
/** Increment indent level */
void incrementIndent()
/** Decrement indent level */
void decrementIndent()
/** Print current indentation */
void printIndent()
/** Set auto-indent mode */
void setAutoIndent(boolean autoIndent)
/** Get current indent level */
int getIndentLevel()
/** Set indent level */
void setIndentLevel(int indentLevel)
}
/**
* Comparator implementation using closures
*/
class ClosureComparator<T> implements Comparator<T> {
/** Create with comparison closure */
ClosureComparator(Closure closure)
/** Compare two objects using closure */
int compare(T o1, T o2)
}
/**
* Utility for working with Groovy collections
*/
class GroovyCollections {
/** Get combinations of collections */
static <T> List<List<T>> combinations(Collection<Collection<T>> collections)
/** Transpose lists (matrix transpose) */
static List transpose(List lists)
/** Get subsequences of a list */
static <T> List<List<T>> subsequences(List<T> items)
/** Permutations of a collection */
static <T> List<List<T>> combinations(List<T> items, int length)
}Usage Examples:
// IndentPrinter
def writer = new StringWriter()
def printer = new IndentPrinter(writer, " ")
printer.println("Level 0")
printer.incrementIndent()
printer.println("Level 1")
printer.incrementIndent()
printer.println("Level 2")
printer.decrementIndent()
printer.println("Back to Level 1")
println writer.toString()
// ClosureComparator
def people = [
[name: "Alice", age: 30],
[name: "Bob", age: 25],
[name: "Charlie", age: 35]
]
// Sort by age
def ageComparator = new ClosureComparator { a, b -> a.age <=> b.age }
people.sort(ageComparator)
// Sort by name length
def nameComparator = new ClosureComparator { a, b -> a.name.length() <=> b.name.length() }
people.sort(nameComparator)
// GroovyCollections
def colors = ["red", "blue"]
def sizes = ["small", "large"]
def materials = ["cotton", "silk"]
def combinations = GroovyCollections.combinations([colors, sizes, materials])
combinations.each { combo ->
println combo.join(" ")
}
// Output: red small cotton, red small silk, red large cotton, etc.
def matrix = [[1, 2, 3], [4, 5, 6]]
def transposed = GroovyCollections.transpose(matrix)
println transposed // [[1, 4], [2, 5], [3, 6]]Install with Tessl CLI
npx tessl i tessl/maven-org-apache-groovy--groovy