0
# Collections and Utilities
1
2
Enhanced collection operations, builder patterns, configuration management, and utility classes that extend Java's standard library with Groovy-specific enhancements.
3
4
## Capabilities
5
6
### Dynamic Objects
7
8
Create and manipulate objects dynamically at runtime.
9
10
```groovy { .api }
11
/**
12
* Dynamic object that allows adding properties and methods at runtime
13
*/
14
class Expando extends GroovyObjectSupport {
15
/** Create empty Expando */
16
Expando()
17
18
/** Create Expando with initial properties */
19
Expando(Map properties)
20
21
/** Get property value dynamically */
22
Object getProperty(String name)
23
24
/** Set property value dynamically */
25
void setProperty(String name, Object value)
26
}
27
```
28
29
**Usage Examples:**
30
31
```groovy
32
// Create dynamic object
33
def person = new Expando()
34
person.name = "Alice"
35
person.age = 30
36
person.greet = { "Hello, I'm ${name}" }
37
38
println person.name // "Alice"
39
println person.greet() // "Hello, I'm Alice"
40
41
// Create with initial properties
42
def car = new Expando([
43
make: "Toyota",
44
model: "Camry",
45
year: 2020,
46
start: { "Starting ${make} ${model}" }
47
])
48
49
println car.start() // "Starting Toyota Camry"
50
51
// Add methods dynamically
52
person.celebrate = { years ->
53
age += years
54
return "Now I'm ${age} years old!"
55
}
56
57
println person.celebrate(1) // "Now I'm 31 years old!"
58
```
59
60
### Builder Support
61
62
Base classes for implementing various builder patterns.
63
64
```groovy { .api }
65
/**
66
* Base class for implementing builder patterns
67
*/
68
abstract class BuilderSupport {
69
/** Create node with name only */
70
protected abstract Object createNode(Object name)
71
72
/** Create node with name and value */
73
protected abstract Object createNode(Object name, Object value)
74
75
/** Create node with name and attributes */
76
protected abstract Object createNode(Object name, Map attributes)
77
78
/** Create node with name, attributes, and value */
79
protected abstract Object createNode(Object name, Map attributes, Object value)
80
81
/** Set parent-child relationship */
82
protected void setParent(Object parent, Object child)
83
84
/** Get current node */
85
protected Object getCurrent()
86
87
/** Set current node */
88
protected void setCurrent(Object current)
89
}
90
91
/**
92
* Builder implementation using factory pattern
93
*/
94
class FactoryBuilderSupport extends BuilderSupport {
95
/** Register factory for node type */
96
void registerFactory(String name, Factory factory)
97
98
/** Register factory with alias */
99
void registerFactory(String name, String groupName, Factory factory)
100
101
/** Register bean factory */
102
void registerBeanFactory(String name, Class beanClass)
103
}
104
```
105
106
**Usage Examples:**
107
108
```groovy
109
// Custom builder implementation
110
class TreeBuilder extends BuilderSupport {
111
private Stack nodeStack = new Stack()
112
113
protected Object createNode(Object name) {
114
return createNode(name, null, null)
115
}
116
117
protected Object createNode(Object name, Object value) {
118
return createNode(name, null, value)
119
}
120
121
protected Object createNode(Object name, Map attributes) {
122
return createNode(name, attributes, null)
123
}
124
125
protected Object createNode(Object name, Map attributes, Object value) {
126
def node = [name: name, attributes: attributes ?: [:], value: value, children: []]
127
128
if (!nodeStack.empty()) {
129
nodeStack.peek().children << node
130
}
131
132
return node
133
}
134
135
protected void setParent(Object parent, Object child) {
136
// Handled in createNode
137
}
138
}
139
140
// Using the custom builder
141
def builder = new TreeBuilder()
142
def tree = builder.root {
143
branch(type: 'main') {
144
leaf('Leaf 1')
145
leaf('Leaf 2', color: 'green')
146
}
147
branch(type: 'secondary') {
148
leaf('Leaf 3')
149
}
150
}
151
```
152
153
### Node Processing
154
155
Tree structure representation and manipulation for XML-like data.
156
157
```groovy { .api }
158
/**
159
* Represents a node in a tree structure (used by XML processing)
160
*/
161
class Node {
162
/** Create node with name */
163
Node(Object name)
164
165
/** Create node with name and value */
166
Node(Object name, Object value)
167
168
/** Create node with name and attributes */
169
Node(Object name, Map attributes)
170
171
/** Create node with parent, name, and value */
172
Node(Node parent, Object name, Object value)
173
174
/** Get node name */
175
Object name()
176
177
/** Get node value */
178
Object value()
179
180
/** Set node value */
181
void setValue(Object value)
182
183
/** Get node attributes */
184
Map attributes()
185
186
/** Get child nodes */
187
List children()
188
189
/** Get parent node */
190
Node parent()
191
192
/** Append child node with name */
193
Node appendNode(Object name)
194
195
/** Append child node with name and value */
196
Node appendNode(Object name, Object value)
197
198
/** Append child node with name and attributes */
199
Node appendNode(Object name, Map attributes)
200
201
/** Remove child node */
202
boolean remove(Node child)
203
204
/** Get attribute value */
205
Object attribute(Object key)
206
207
/** Get text content */
208
String text()
209
210
/** Find all nodes matching closure */
211
List findAll(Closure closure)
212
213
/** Find first node matching closure */
214
Node find(Closure closure)
215
}
216
217
/**
218
* List of Node objects with additional query capabilities
219
*/
220
class NodeList extends ArrayList<Node> {
221
/** Get nodes by name */
222
NodeList getAt(String name)
223
224
/** Get text content of all nodes */
225
String text()
226
227
/** Find all nodes matching closure */
228
NodeList findAll(Closure closure)
229
230
/** Get attribute values */
231
List getAttribute(String name)
232
}
233
```
234
235
### Configuration Management
236
237
Hierarchical configuration objects with nested property support.
238
239
```groovy { .api }
240
/**
241
* Configuration object supporting hierarchical properties
242
*/
243
class ConfigObject implements Map<String, Object> {
244
/** Create empty ConfigObject */
245
ConfigObject()
246
247
/** Check if config is empty */
248
boolean isEmpty()
249
250
/** Get property using dot notation */
251
Object getProperty(String name)
252
253
/** Set property using dot notation */
254
void setProperty(String name, Object value)
255
256
/** Merge with another ConfigObject */
257
ConfigObject merge(ConfigObject other)
258
259
/** Convert to Properties */
260
Properties toProperties()
261
262
/** Convert to Properties with prefix */
263
Properties toProperties(String prefix)
264
265
/** Flatten to Map */
266
Map flatten()
267
268
/** Flatten with custom separator */
269
Map flatten(String separator)
270
}
271
```
272
273
**Usage Examples:**
274
275
```groovy
276
// Create configuration
277
def config = new ConfigObject()
278
config.database.url = "jdbc:mysql://localhost:3306/mydb"
279
config.database.username = "user"
280
config.database.password = "pass"
281
config.server.port = 8080
282
config.server.host = "localhost"
283
284
// Access nested properties
285
println config.database.url // "jdbc:mysql://localhost:3306/mydb"
286
println config.server.port // 8080
287
288
// Map-style access
289
println config['database']['username'] // "user"
290
291
// Convert to Properties
292
def props = config.toProperties()
293
props.each { key, value ->
294
println "$key = $value"
295
}
296
297
// Merge configurations
298
def defaultConfig = new ConfigObject()
299
defaultConfig.server.timeout = 30
300
defaultConfig.server.retries = 3
301
302
def finalConfig = defaultConfig.merge(config)
303
println finalConfig.server.timeout // 30
304
println finalConfig.server.port // 8080
305
```
306
307
### Observable Collections
308
309
Collections that fire events when modified.
310
311
```groovy { .api }
312
/**
313
* List implementation that fires events on changes
314
*/
315
class ObservableList<E> extends ArrayList<E> {
316
/** Add property change listener */
317
void addPropertyChangeListener(PropertyChangeListener listener)
318
319
/** Remove property change listener */
320
void removePropertyChangeListener(PropertyChangeListener listener)
321
322
/** Add property change listener for specific property */
323
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
324
325
/** Remove property change listener for specific property */
326
void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
327
328
/** Get all property change listeners */
329
PropertyChangeListener[] getPropertyChangeListeners()
330
331
/** Fire property change event */
332
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue)
333
}
334
335
/**
336
* Map implementation that fires events on changes
337
*/
338
class ObservableMap<K, V> extends HashMap<K, V> {
339
/** Add property change listener */
340
void addPropertyChangeListener(PropertyChangeListener listener)
341
342
/** Remove property change listener */
343
void removePropertyChangeListener(PropertyChangeListener listener)
344
345
/** Add property change listener for specific property */
346
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
347
348
/** Get all property change listeners */
349
PropertyChangeListener[] getPropertyChangeListeners()
350
}
351
352
/**
353
* Set implementation that fires events on changes
354
*/
355
class ObservableSet<E> extends HashSet<E> {
356
/** Add property change listener */
357
void addPropertyChangeListener(PropertyChangeListener listener)
358
359
/** Remove property change listener */
360
void removePropertyChangeListener(PropertyChangeListener listener)
361
362
/** Get all property change listeners */
363
PropertyChangeListener[] getPropertyChangeListeners()
364
}
365
```
366
367
**Usage Examples:**
368
369
```groovy
370
import java.beans.PropertyChangeListener
371
372
// Observable list
373
def list = new ObservableList()
374
list.addPropertyChangeListener { event ->
375
println "List changed: ${event.propertyName} from ${event.oldValue} to ${event.newValue}"
376
}
377
378
list.add("item1") // Fires event
379
list.add("item2") // Fires event
380
list.remove("item1") // Fires event
381
382
// Observable map
383
def map = new ObservableMap()
384
map.addPropertyChangeListener("key1") { event ->
385
println "Key1 changed from ${event.oldValue} to ${event.newValue}"
386
}
387
388
map.put("key1", "value1") // Fires event for key1
389
map.put("key2", "value2") // No event (no listener for key2)
390
map.put("key1", "newvalue") // Fires event for key1
391
```
392
393
### Utility Classes
394
395
Various utility classes for common operations.
396
397
```groovy { .api }
398
/**
399
* PrintWriter that automatically handles indentation
400
*/
401
class IndentPrinter extends PrintWriter {
402
/** Create with Writer and indent string */
403
IndentPrinter(Writer writer, String indent)
404
405
/** Create with Writer, default indent */
406
IndentPrinter(Writer writer)
407
408
/** Increment indent level */
409
void incrementIndent()
410
411
/** Decrement indent level */
412
void decrementIndent()
413
414
/** Print current indentation */
415
void printIndent()
416
417
/** Set auto-indent mode */
418
void setAutoIndent(boolean autoIndent)
419
420
/** Get current indent level */
421
int getIndentLevel()
422
423
/** Set indent level */
424
void setIndentLevel(int indentLevel)
425
}
426
427
/**
428
* Comparator implementation using closures
429
*/
430
class ClosureComparator<T> implements Comparator<T> {
431
/** Create with comparison closure */
432
ClosureComparator(Closure closure)
433
434
/** Compare two objects using closure */
435
int compare(T o1, T o2)
436
}
437
438
/**
439
* Utility for working with Groovy collections
440
*/
441
class GroovyCollections {
442
/** Get combinations of collections */
443
static <T> List<List<T>> combinations(Collection<Collection<T>> collections)
444
445
/** Transpose lists (matrix transpose) */
446
static List transpose(List lists)
447
448
/** Get subsequences of a list */
449
static <T> List<List<T>> subsequences(List<T> items)
450
451
/** Permutations of a collection */
452
static <T> List<List<T>> combinations(List<T> items, int length)
453
}
454
```
455
456
**Usage Examples:**
457
458
```groovy
459
// IndentPrinter
460
def writer = new StringWriter()
461
def printer = new IndentPrinter(writer, " ")
462
463
printer.println("Level 0")
464
printer.incrementIndent()
465
printer.println("Level 1")
466
printer.incrementIndent()
467
printer.println("Level 2")
468
printer.decrementIndent()
469
printer.println("Back to Level 1")
470
471
println writer.toString()
472
473
// ClosureComparator
474
def people = [
475
[name: "Alice", age: 30],
476
[name: "Bob", age: 25],
477
[name: "Charlie", age: 35]
478
]
479
480
// Sort by age
481
def ageComparator = new ClosureComparator { a, b -> a.age <=> b.age }
482
people.sort(ageComparator)
483
484
// Sort by name length
485
def nameComparator = new ClosureComparator { a, b -> a.name.length() <=> b.name.length() }
486
people.sort(nameComparator)
487
488
// GroovyCollections
489
def colors = ["red", "blue"]
490
def sizes = ["small", "large"]
491
def materials = ["cotton", "silk"]
492
493
def combinations = GroovyCollections.combinations([colors, sizes, materials])
494
combinations.each { combo ->
495
println combo.join(" ")
496
}
497
// Output: red small cotton, red small silk, red large cotton, etc.
498
499
def matrix = [[1, 2, 3], [4, 5, 6]]
500
def transposed = GroovyCollections.transpose(matrix)
501
println transposed // [[1, 4], [2, 5], [3, 6]]
502
```