0
# Collections and Utilities
1
2
Enhanced collection classes, observable data structures, and utility functions that extend Java's collection framework with Groovy-specific features and dynamic behavior. These utilities provide event-driven collections, default value handling, and enhanced data structure capabilities.
3
4
## Capabilities
5
6
### Observable Collections
7
8
Collections that fire property change events when modified.
9
10
```java { .api }
11
class ObservableList<E> extends ArrayList<E> {
12
/**
13
* Creates an empty observable list.
14
*/
15
ObservableList();
16
17
/**
18
* Creates an observable list with initial capacity.
19
*/
20
ObservableList(int initialCapacity);
21
22
/**
23
* Creates an observable list from another collection.
24
*/
25
ObservableList(Collection<? extends E> c);
26
27
/**
28
* Adds a property change listener.
29
*/
30
void addPropertyChangeListener(PropertyChangeListener listener);
31
32
/**
33
* Removes a property change listener.
34
*/
35
void removePropertyChangeListener(PropertyChangeListener listener);
36
37
/**
38
* Adds a property change listener for a specific property.
39
*/
40
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
41
42
/**
43
* Removes a property change listener for a specific property.
44
*/
45
void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
46
47
/**
48
* Gets all property change listeners.
49
*/
50
PropertyChangeListener[] getPropertyChangeListeners();
51
52
/**
53
* Gets property change listeners for a specific property.
54
*/
55
PropertyChangeListener[] getPropertyChangeListeners(String propertyName);
56
57
/**
58
* Fires a property change event.
59
*/
60
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue);
61
62
/**
63
* Fires an indexed property change event.
64
*/
65
protected void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue);
66
}
67
68
class ObservableMap<K, V> extends LinkedHashMap<K, V> {
69
/**
70
* Creates an empty observable map.
71
*/
72
ObservableMap();
73
74
/**
75
* Creates an observable map with initial capacity.
76
*/
77
ObservableMap(int initialCapacity);
78
79
/**
80
* Creates an observable map from another map.
81
*/
82
ObservableMap(Map<? extends K, ? extends V> m);
83
84
/**
85
* Adds a property change listener.
86
*/
87
void addPropertyChangeListener(PropertyChangeListener listener);
88
89
/**
90
* Removes a property change listener.
91
*/
92
void removePropertyChangeListener(PropertyChangeListener listener);
93
94
/**
95
* Adds a property change listener for a specific property.
96
*/
97
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
98
99
/**
100
* Removes a property change listener for a specific property.
101
*/
102
void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
103
104
/**
105
* Gets all property change listeners.
106
*/
107
PropertyChangeListener[] getPropertyChangeListeners();
108
109
/**
110
* Fires a property change event.
111
*/
112
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue);
113
}
114
115
class ObservableSet<E> extends LinkedHashSet<E> {
116
/**
117
* Creates an empty observable set.
118
*/
119
ObservableSet();
120
121
/**
122
* Creates an observable set with initial capacity.
123
*/
124
ObservableSet(int initialCapacity);
125
126
/**
127
* Creates an observable set from another collection.
128
*/
129
ObservableSet(Collection<? extends E> c);
130
131
/**
132
* Adds a property change listener.
133
*/
134
void addPropertyChangeListener(PropertyChangeListener listener);
135
136
/**
137
* Removes a property change listener.
138
*/
139
void removePropertyChangeListener(PropertyChangeListener listener);
140
141
/**
142
* Adds a property change listener for a specific property.
143
*/
144
void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
145
146
/**
147
* Removes a property change listener for a specific property.
148
*/
149
void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
150
151
/**
152
* Gets all property change listeners.
153
*/
154
PropertyChangeListener[] getPropertyChangeListeners();
155
}
156
```
157
158
### Default Value Collections
159
160
Collections that provide default values for missing keys or out-of-bounds access.
161
162
```java { .api }
163
class ListWithDefault<T> implements List<T> {
164
/**
165
* Creates a list with default value provider.
166
*/
167
static <T> ListWithDefault<T> withDefault(Closure<T> defaultValue);
168
169
/**
170
* Creates a list with default value provider from existing list.
171
*/
172
static <T> ListWithDefault<T> withDefault(List<T> list, Closure<T> defaultValue);
173
174
/**
175
* Creates a list with lazy default value provider.
176
*/
177
static <T> ListWithDefault<T> withLazyDefault(Closure<T> defaultValue);
178
179
/**
180
* Creates a list with lazy default value provider from existing list.
181
*/
182
static <T> ListWithDefault<T> withLazyDefault(List<T> list, Closure<T> defaultValue);
183
184
/**
185
* Creates a list with eager default value provider.
186
*/
187
static <T> ListWithDefault<T> withEagerDefault(Closure<T> defaultValue);
188
189
/**
190
* Creates a list with eager default value provider from existing list.
191
*/
192
static <T> ListWithDefault<T> withEagerDefault(List<T> list, Closure<T> defaultValue);
193
194
/**
195
* Gets the default value for the given index.
196
*/
197
T getDefaultValue(int index);
198
199
/**
200
* Checks if the default value is lazy.
201
*/
202
boolean isLazyDefaultValues();
203
204
/**
205
* Checks if the default value is eager.
206
*/
207
boolean isEagerDefaultValues();
208
}
209
210
class MapWithDefault<K, V> implements Map<K, V> {
211
/**
212
* Creates a map with default value provider.
213
*/
214
static <K, V> MapWithDefault<K, V> withDefault(Closure<V> defaultValue);
215
216
/**
217
* Creates a map with default value provider from existing map.
218
*/
219
static <K, V> MapWithDefault<K, V> withDefault(Map<K, V> map, Closure<V> defaultValue);
220
221
/**
222
* Creates a map with lazy default value provider.
223
*/
224
static <K, V> MapWithDefault<K, V> withLazyDefault(Closure<V> defaultValue);
225
226
/**
227
* Creates a map with lazy default value provider from existing map.
228
*/
229
static <K, V> MapWithDefault<K, V> withLazyDefault(Map<K, V> map, Closure<V> defaultValue);
230
231
/**
232
* Creates a map with eager default value provider.
233
*/
234
static <K, V> MapWithDefault<K, V> withEagerDefault(Closure<V> defaultValue);
235
236
/**
237
* Creates a map with eager default value provider from existing map.
238
*/
239
static <K, V> MapWithDefault<K, V> withEagerDefault(Map<K, V> map, Closure<V> defaultValue);
240
241
/**
242
* Gets the default value for the given key.
243
*/
244
V getDefaultValue(K key);
245
246
/**
247
* Checks if the default value is lazy.
248
*/
249
boolean isLazyDefaultValues();
250
251
/**
252
* Checks if the default value is eager.
253
*/
254
boolean isEagerDefaultValues();
255
}
256
```
257
258
### Tree Node Utilities
259
260
Generic tree node implementation for data processing and XML handling.
261
262
```java { .api }
263
class Node implements Serializable, Cloneable {
264
/**
265
* Creates a Node with the given name.
266
*/
267
Node(Object name);
268
269
/**
270
* Creates a Node with name and value.
271
*/
272
Node(Object name, Object value);
273
274
/**
275
* Creates a Node with name and attributes.
276
*/
277
Node(Object name, Map<String, String> attributes);
278
279
/**
280
* Creates a Node with name, attributes, and value.
281
*/
282
Node(Object name, Map<String, String> attributes, Object value);
283
284
/**
285
* Creates a Node with parent, name, and value.
286
*/
287
Node(Node parent, Object name, Object value);
288
289
/**
290
* Creates a Node with parent, name, attributes, and value.
291
*/
292
Node(Node parent, Object name, Map<String, String> attributes, Object value);
293
294
/**
295
* Gets the name of this node.
296
*/
297
Object name();
298
299
/**
300
* Gets the value of this node.
301
*/
302
Object value();
303
304
/**
305
* Sets the value of this node.
306
*/
307
void setValue(Object value);
308
309
/**
310
* Gets the attributes of this node.
311
*/
312
Map<String, String> attributes();
313
314
/**
315
* Gets an attribute value.
316
*/
317
Object attribute(Object key);
318
319
/**
320
* Gets all child nodes.
321
*/
322
List<Node> children();
323
324
/**
325
* Gets the parent node.
326
*/
327
Node parent();
328
329
/**
330
* Sets the parent node.
331
*/
332
void setParent(Node parent);
333
334
/**
335
* Gets the text content of this node and its children.
336
*/
337
String text();
338
339
/**
340
* Gets child nodes with the given name.
341
*/
342
NodeList get(Object key);
343
344
/**
345
* Gets child node at the given index.
346
*/
347
Object get(int index);
348
349
/**
350
* Gets a property value (attribute or child).
351
*/
352
Object getProperty(String key);
353
354
/**
355
* Sets a property value (creates child or sets attribute).
356
*/
357
void setProperty(String key, Object value);
358
359
/**
360
* Appends a child node.
361
*/
362
Node append(Node child);
363
364
/**
365
* Removes a child node.
366
*/
367
boolean remove(Node child);
368
369
/**
370
* Adds a child node.
371
*/
372
void add(Node child);
373
374
/**
375
* Replaces this node with another.
376
*/
377
void replaceNode(Node replacement);
378
379
/**
380
* Finds child nodes matching the closure condition.
381
*/
382
NodeList depthFirst(Closure closure);
383
384
/**
385
* Finds child nodes in breadth-first order matching the closure.
386
*/
387
NodeList breadthFirst(Closure closure);
388
}
389
390
class NodeBuilder extends BuilderSupport {
391
/**
392
* Creates a NodeBuilder.
393
*/
394
NodeBuilder();
395
396
/**
397
* Creates a named node.
398
*/
399
protected Object createNode(Object name);
400
401
/**
402
* Creates a named node with value.
403
*/
404
protected Object createNode(Object name, Object value);
405
406
/**
407
* Creates a named node with attributes.
408
*/
409
protected Object createNode(Object name, Map attributes);
410
411
/**
412
* Creates a named node with attributes and value.
413
*/
414
protected Object createNode(Object name, Map attributes, Object value);
415
416
/**
417
* Sets the parent-child relationship.
418
*/
419
protected void setParent(Object parent, Object child);
420
421
/**
422
* Called when node creation is complete.
423
*/
424
protected void nodeCompleted(Object parent, Object node);
425
}
426
```
427
428
### Inspection Utilities
429
430
Object inspection and introspection utilities.
431
432
```java { .api }
433
class Inspector {
434
/**
435
* Creates an Inspector for the given object.
436
*/
437
Inspector(Object objectUnderInspection);
438
439
/**
440
* Inspects the object and returns a string representation.
441
*/
442
String inspect();
443
444
/**
445
* Prints the inspection to the console.
446
*/
447
void print();
448
449
/**
450
* Prints the inspection to a PrintStream.
451
*/
452
void print(PrintStream out);
453
454
/**
455
* Gets inspection data as a list of strings.
456
*/
457
String[] getPropertyInfo();
458
459
/**
460
* Gets inspection data as a list of strings with sorting.
461
*/
462
String[] getPropertyInfo(Comparator<String> comparator);
463
464
/**
465
* Gets meta information about the object's class.
466
*/
467
String[] getMetaInfo();
468
469
/**
470
* Gets public field information.
471
*/
472
String[] getPublicFieldInfo();
473
474
/**
475
* Gets property information.
476
*/
477
String[] getPropertyInfo();
478
}
479
```
480
481
### Logging Utilities
482
483
Simple logging support for Groovy applications.
484
485
```java { .api }
486
class Log {
487
/**
488
* Gets a logger for the given class.
489
*/
490
static Logger getLogger(Class<?> clazz);
491
492
/**
493
* Gets a logger with the given name.
494
*/
495
static Logger getLogger(String name);
496
497
/**
498
* Sets the logging level.
499
*/
500
static void setLevel(Level level);
501
502
/**
503
* Gets the current logging level.
504
*/
505
static Level getLevel();
506
}
507
508
interface Logger {
509
/**
510
* Logs a debug message.
511
*/
512
void debug(Object message);
513
514
/**
515
* Logs an info message.
516
*/
517
void info(Object message);
518
519
/**
520
* Logs a warning message.
521
*/
522
void warn(Object message);
523
524
/**
525
* Logs an error message.
526
*/
527
void error(Object message);
528
529
/**
530
* Logs an error message with throwable.
531
*/
532
void error(Object message, Throwable t);
533
534
/**
535
* Checks if debug logging is enabled.
536
*/
537
boolean isDebugEnabled();
538
539
/**
540
* Checks if info logging is enabled.
541
*/
542
boolean isInfoEnabled();
543
544
/**
545
* Checks if warn logging is enabled.
546
*/
547
boolean isWarnEnabled();
548
549
/**
550
* Checks if error logging is enabled.
551
*/
552
boolean isErrorEnabled();
553
}
554
```
555
556
## Usage Examples
557
558
### Observable Collections
559
560
```java
561
import groovy.util.ObservableList;
562
import groovy.util.ObservableMap;
563
import java.beans.PropertyChangeListener;
564
import java.beans.PropertyChangeEvent;
565
566
// Create observable list with listener
567
ObservableList<String> list = new ObservableList<>();
568
list.addPropertyChangeListener(new PropertyChangeListener() {
569
public void propertyChange(PropertyChangeEvent evt) {
570
System.out.println("Property " + evt.getPropertyName() +
571
" changed from " + evt.getOldValue() +
572
" to " + evt.getNewValue());
573
}
574
});
575
576
// Add elements - will fire events
577
list.add("first");
578
list.add("second");
579
list.set(0, "modified");
580
581
// Create observable map
582
ObservableMap<String, Integer> map = new ObservableMap<>();
583
map.addPropertyChangeListener("size", new PropertyChangeListener() {
584
public void propertyChange(PropertyChangeEvent evt) {
585
System.out.println("Map size changed to " + evt.getNewValue());
586
}
587
});
588
589
map.put("one", 1);
590
map.put("two", 2);
591
```
592
593
### Default Value Collections
594
595
```java
596
import groovy.util.ListWithDefault;
597
import groovy.util.MapWithDefault;
598
import groovy.lang.Closure;
599
600
// Create list with default values
601
ListWithDefault<String> list = ListWithDefault.withDefault(new Closure<String>(null) {
602
public String doCall(Object index) {
603
return "default-" + index;
604
}
605
});
606
607
// Access beyond bounds returns default value
608
System.out.println(list.get(5)); // Prints: default-5
609
610
// Create map with default values
611
MapWithDefault<String, List<String>> map = MapWithDefault.withDefault(new Closure<List<String>>(null) {
612
public List<String> doCall(Object key) {
613
return new ArrayList<String>();
614
}
615
});
616
617
// Access missing key returns default value
618
List<String> defaultList = map.get("nonexistent");
619
defaultList.add("item");
620
map.put("nonexistent", defaultList);
621
```
622
623
### Tree Node Processing
624
625
```java
626
import groovy.util.Node;
627
import groovy.util.NodeBuilder;
628
import groovy.util.NodeList;
629
630
// Create node tree with builder
631
NodeBuilder builder = new NodeBuilder();
632
Node root = (Node) builder.invokeMethod("root", new Object[]{});
633
634
Node person = new Node(root, "person", new HashMap<String, String>());
635
person.attributes().put("id", "1");
636
637
new Node(person, "name", "John Doe");
638
new Node(person, "age", "30");
639
new Node(person, "email", "john@example.com");
640
641
// Navigate and process
642
System.out.println("Root name: " + root.name());
643
System.out.println("Person ID: " + person.attribute("id"));
644
645
NodeList children = root.get("person");
646
for (Node child : children) {
647
System.out.println("Child: " + child.name());
648
649
NodeList nameNodes = child.get("name");
650
if (!nameNodes.isEmpty()) {
651
System.out.println("Name: " + ((Node)nameNodes.get(0)).value());
652
}
653
}
654
655
// Find nodes using closure
656
NodeList foundNodes = root.depthFirst(new Closure<Boolean>(null) {
657
public Boolean doCall(Object node) {
658
return ((Node)node).name().equals("email");
659
}
660
});
661
662
for (Node found : foundNodes) {
663
System.out.println("Found email: " + found.value());
664
}
665
```
666
667
### Object Inspection
668
669
```java
670
import groovy.inspect.Inspector;
671
672
// Inspect an object
673
String testString = "Hello World";
674
Inspector inspector = new Inspector(testString);
675
676
// Print inspection to console
677
inspector.print();
678
679
// Get inspection data
680
String[] propertyInfo = inspector.getPropertyInfo();
681
for (String info : propertyInfo) {
682
System.out.println(info);
683
}
684
685
// Get meta information
686
String[] metaInfo = inspector.getMetaInfo();
687
for (String info : metaInfo) {
688
System.out.println(info);
689
}
690
```