NIO extensions for Apache Groovy providing enhanced file system operations and path handling
—
Handle Java object serialization and deserialization with support for custom class loaders and closure-based processing for safe resource management.
Create and manage ObjectOutputStream objects for writing serializable objects to files.
/**
* Create an object output stream for this path
* @param self a Path object
* @return an object output stream
* @throws IOException if an IOException occurs
*/
ObjectOutputStream newObjectOutputStream(Path self);
/**
* Create a new ObjectOutputStream for this path and then pass it to the closure.
* This method ensures the stream is closed after the closure returns
* @param self a Path
* @param closure a closure
* @return the value returned by the closure
* @throws IOException if an IOException occurs
*/
<T> T withObjectOutputStream(Path self, Closure<T> closure);Usage Examples:
import java.nio.file.Path
import java.nio.file.Paths
Path objectFile = Paths.get("data.ser")
// Create object output stream (manual resource management)
ObjectOutputStream objOut = objectFile.newObjectOutputStream()
try {
objOut.writeObject("Hello, World!")
objOut.writeObject(42)
objOut.writeObject([1, 2, 3])
objOut.flush()
} finally {
objOut.close()
}
// Automatic resource management with closure
objectFile.withObjectOutputStream { objOut ->
objOut.writeObject("String data")
objOut.writeObject(new Date())
objOut.writeObject([name: "John", age: 30])
// Write multiple objects
def people = [
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
]
objOut.writeObject(people)
}
// Serialize custom objects
class Configuration implements Serializable {
String hostname
int port
Map<String, String> properties
}
Path configFile = Paths.get("config.ser")
def config = new Configuration(
hostname: "localhost",
port: 8080,
properties: [debug: "true", timeout: "30"]
)
configFile.withObjectOutputStream { objOut ->
objOut.writeObject(config)
}Create and manage ObjectInputStream objects for reading serializable objects from files.
/**
* Create an object input stream for this file
* @param self a Path object
* @return an object input stream
* @throws IOException if an IOException occurs
*/
ObjectInputStream newObjectInputStream(Path self);
/**
* Create an object input stream for this path using the given class loader
* @param self a Path object
* @param classLoader the class loader to use when loading the class
* @return an object input stream
* @throws IOException if an IOException occurs
*/
ObjectInputStream newObjectInputStream(Path self, ClassLoader classLoader);
/**
* Create a new ObjectInputStream for this file and pass it to the closure.
* This method ensures the stream is closed after the closure returns
* @param path a Path
* @param closure a closure
* @return the value returned by the closure
* @throws IOException if an IOException occurs
*/
<T> T withObjectInputStream(Path path, Closure<T> closure);
/**
* Create a new ObjectInputStream for this file associated with the given class loader and pass it to the closure.
* This method ensures the stream is closed after the closure returns
* @param self a Path
* @param classLoader the class loader to use when loading the class
* @param closure a closure
* @return the value returned by the closure
* @throws IOException if an IOException occurs
*/
<T> T withObjectInputStream(Path self, ClassLoader classLoader, Closure<T> closure);Usage Examples:
import java.nio.file.Path
import java.nio.file.Paths
Path objectFile = Paths.get("data.ser")
// Create object input stream (manual resource management)
ObjectInputStream objIn = objectFile.newObjectInputStream()
try {
String stringData = objIn.readObject()
Integer intData = objIn.readObject()
List listData = objIn.readObject()
println "String: ${stringData}"
println "Integer: ${intData}"
println "List: ${listData}"
} finally {
objIn.close()
}
// Automatic resource management with closure
def objects = objectFile.withObjectInputStream { objIn ->
def result = []
try {
while (true) {
result << objIn.readObject()
}
} catch (EOFException e) {
// Expected when reaching end of file
}
return result
}
println "Read ${objects.size()} objects: ${objects}"
// Deserialize with custom class loader
ClassLoader customLoader = new URLClassLoader([new File("custom-classes").toURI().toURL()] as URL[])
objectFile.withObjectInputStream(customLoader) { objIn ->
def customObject = objIn.readObject()
println "Loaded custom object: ${customObject}"
}
// Read configuration object
Path configFile = Paths.get("config.ser")
Configuration config = configFile.withObjectInputStream { objIn ->
objIn.readObject() as Configuration
}
println "Loaded config: ${config.hostname}:${config.port}"
config.properties.each { key, value ->
println " ${key} = ${value}"
}Iterate through objects in a serialized file using closures.
/**
* Iterates through the given file object by object
* @param self a Path object
* @param closure a closure
* @throws IOException if an IOException occurs
* @throws ClassNotFoundException if the class is not found
*/
void eachObject(Path self, Closure closure);Usage Examples:
import java.nio.file.Path
import java.nio.file.Paths
Path objectFile = Paths.get("multiple-objects.ser")
// First, write multiple objects
objectFile.withObjectOutputStream { objOut ->
objOut.writeObject("First object")
objOut.writeObject(42)
objOut.writeObject([name: "Alice", age: 25])
objOut.writeObject(new Date())
objOut.writeObject([1, 2, 3, 4, 5])
}
// Iterate through all objects in the file
objectFile.eachObject { obj ->
println "Object type: ${obj.class.simpleName}, value: ${obj}"
}
// Process specific object types
objectFile.eachObject { obj ->
switch (obj) {
case String:
println "Found string: '${obj}'"
break
case Number:
println "Found number: ${obj} (${obj.class.simpleName})"
break
case List:
println "Found list with ${obj.size()} elements: ${obj}"
break
case Map:
println "Found map with keys: ${obj.keySet()}"
break
case Date:
println "Found date: ${obj.format('yyyy-MM-dd HH:mm:ss')}"
break
default:
println "Found other object: ${obj} (${obj.class.name})"
}
}
// Count objects by type
def typeCounts = [:]
objectFile.eachObject { obj ->
String typeName = obj.class.simpleName
typeCounts[typeName] = (typeCounts[typeName] ?: 0) + 1
}
println "Object type summary:"
typeCounts.each { type, count ->
println " ${type}: ${count}"
}
// Filter and collect specific objects
def stringObjects = []
def numberObjects = []
objectFile.eachObject { obj ->
if (obj instanceof String) {
stringObjects << obj
} else if (obj instanceof Number) {
numberObjects << obj
}
}
println "String objects: ${stringObjects}"
println "Number objects: ${numberObjects}"Advanced examples demonstrating real-world usage patterns.
Usage Examples:
import java.nio.file.Path
import java.nio.file.Paths
// Serialize application state
class ApplicationState implements Serializable {
String version
Map<String, Object> settings
List<String> recentFiles
Date lastSaved
}
Path stateFile = Paths.get("app-state.ser")
// Save application state
def currentState = new ApplicationState(
version: "1.0.0",
settings: [theme: "dark", language: "en", autoSave: true],
recentFiles: ["/home/user/doc1.txt", "/home/user/doc2.txt"],
lastSaved: new Date()
)
stateFile.withObjectOutputStream { objOut ->
objOut.writeObject(currentState)
}
// Load application state
ApplicationState loadedState = stateFile.withObjectInputStream { objIn ->
objIn.readObject() as ApplicationState
}
println "Loaded application state:"
println " Version: ${loadedState.version}"
println " Settings: ${loadedState.settings}"
println " Recent files: ${loadedState.recentFiles}"
println " Last saved: ${loadedState.lastSaved}"
// Serialize a cache of objects
Path cacheFile = Paths.get("object-cache.ser")
// Write cache
def cache = [
"user:123": [id: 123, name: "Alice", email: "alice@example.com"],
"user:456": [id: 456, name: "Bob", email: "bob@example.com"],
"config:main": [timeout: 30, retries: 3, debug: false]
]
cacheFile.withObjectOutputStream { objOut ->
cache.each { key, value ->
objOut.writeObject([key: key, value: value])
}
}
// Read cache
def loadedCache = [:]
cacheFile.eachObject { entry ->
loadedCache[entry.key] = entry.value
}
println "Loaded cache entries:"
loadedCache.each { key, value ->
println " ${key}: ${value}"
}
// Serialize with versioning for backward compatibility
class VersionedData implements Serializable {
private static final long serialVersionUID = 1L
int version = 1
String data
Map<String, Object> metadata
// Custom serialization for version handling
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject()
}
private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
input.defaultReadObject()
// Handle version-specific logic here
if (version < 1) {
// Upgrade old data format
metadata = metadata ?: [:]
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-nio