# Serialization & I/O
This page covers turning a Tree into text or binary — and parsing it back — to and from Strings,
byte arrays, files, streams and channels. JSON is the default format; other formats are selected by
name and may require an extra dependency (see
Format availability at the bottom).
For building and reading the in-memory structure itself, see Data Manipulation and Reading values.
import io.datatree.Tree;
import java.io.File;
import java.net.URL;
# To a String
toString() (no arguments) produces pretty-printed JSON, including the metadata block:
Tree node = new Tree();
node.put("address.city", "Phoenix");
System.out.println(node.toString());
{
"address":{
"city":"Phoenix"
}
}
The overloads give you control over pretty-printing, the format, and whether the metadata block is written:
node.toString(); // pretty JSON, WITH meta
node.toString(true); // pretty JSON, WITHOUT meta
node.toString(false); // compact JSON, WITHOUT meta
node.toString("json"); // named format, compact, WITHOUT meta
node.toString("json", true); // named format, pretty, WITHOUT meta
node.toString("json", true, true); // named format, pretty, WITH meta
Compact JSON is a single line:
System.out.println(node.toString(false));
// {"address":{"city":"Phoenix"}}
Any registered format name works. The built-in debug format renders a readable type-annotated
dump — handy for logging:
Tree node = new Tree().put("a", 1).put("b", "c");
System.out.println(node.toString("debug"));
Map:
a -> Number: 1
b -> class java.lang.String: c
Other text formats — yaml, xml, csv, tsv, toml, properties — use the same call,
node.toString("yaml"), once the datatree-adapters artifact is on the classpath.
# To binary
toBinary() returns a JSON byte array (without meta); toBinary(format[, insertMeta]) selects a
binary format. The built-in java format (standard Java serialization) is always available and
round-trips losslessly:
Tree node = new Tree().put("a", 1).put("b", "hello");
byte[] bytes = node.toBinary("java");
Tree copy = new Tree(bytes, "java");
System.out.println(copy.toString(true));
// { "a":1, "b":"hello" }
The compact binary formats — cbor, bson, smile, msgpack, ion, kryo — are used the same
way (node.toBinary("cbor")) once datatree-adapters (and that format's backing library) is
present. See Performance of binary APIs for a comparison.
# To a file, stream or channel
writeTo(String path) (or writeTo(File)) writes the document, guessing the format from the file
extension and defaulting to JSON when the extension is unknown:
Tree node = new Tree().put("key", "value");
node.writeTo("/path/to/file.json"); // JSON, from the .json extension
node.writeTo("/path/to/file.cbor"); // CBOR (needs datatree-adapters)
Pass the format (and insertMeta) explicitly to override the guess, or write to an OutputStream /
WritableByteChannel:
node.writeTo(new File("data.bin"), "java");
node.writeTo(outputStream, "json");
node.writeTo(byteChannel, "json");
# Parsing / loading
Every output path has a matching input path. Construct a Tree from a String, a byte array, a
File, a URL, an InputStream or a ReadableByteChannel:
Tree a = new Tree(jsonString); // JSON String
Tree b = new Tree(yamlString, "yaml"); // String + format
Tree c = new Tree(jsonBytes); // JSON byte[]
Tree d = new Tree(cborBytes, "cbor"); // byte[] + format
Tree e = new Tree(new File("data.yaml")); // format from extension
Tree f = new Tree(new URL("http://host/data.json")); // format from extension
Tree g = new Tree(inputStream, "json");
Tree h = new Tree(byteChannel, "json");
A round-trip through a file:
Tree node = new Tree().put("key", "value");
node.writeTo("/tmp/data.json");
Tree loaded = new Tree(new File("/tmp/data.json"));
System.out.println(loaded.toString(true));
// { "key":"value" }
For File and URL sources the format is taken from the extension (.json, .yaml/.yml,
.bson, .cbor, …). If the extension is missing, unrecognized, or its adapter is not on the
classpath, the source is parsed as JSON. To force a specific format, use the two-argument
constructor.
# The _meta block
A document may carry an optional metadata node alongside its body — see
A record + its metadata block for how to build
one with getMeta(). The insertMeta flag controls whether that block is serialized:
toString()andtoString(format, pretty, true)include the metadata (under the_metakey).toString(boolean),toString(format),toString(format, pretty),toBinary()andtoBinary(format)omit it.
Tree rsp = new Tree().put("result", "ok");
rsp.getMeta().put("$statusCode", 200);
rsp.toString(); // { "result":"ok", "_meta":{ "$statusCode":200 } }
rsp.toString(true); // { "result":"ok" }
The key used for the metadata block defaults to _meta and can be changed with the
-Ddatatree.meta.name=… system property.
# Format availability & dependencies
The datatree-core artifact ships only three built-in formats, available with no extra
dependency:
| Format | Kind | Notes |
|---|---|---|
json | text | The default. Reader + writer. |
java | binary | Standard Java serialization. |
debug | text | Human-readable, type-annotated dump (output only). |
All other formats are provided by the datatree-adapters artifact (plus the backing library for
that format). Add it to use them:
<dependency>
<groupId>com.github.berkesa</groupId>
<artifactId>datatree-adapters</artifactId>
<version>2.0.0</version>
</dependency>
| Format | Page | Kind |
|---|---|---|
| JSON | format-json.html | text (built-in) |
| XML | format-xml.html | text |
| YAML | format-yaml.html | text |
| TOML | format-toml.html | text |
| Java Properties | format-properties.html | text |
| CSV | format-csv.html | text |
| TSV | format-tsv.html | text |
| CBOR | format-cbor.html | binary |
| BSON | format-bson.html | binary |
| SMILE | format-smile.html | binary |
| Amazon ION | format-ion.html | binary |
| MessagePack | format-msgpack.html | binary |
| Java Serialization | format-java.html | binary (built-in) |
| Kryo | format-kryo.html | binary |
If a format's adapter is missing, the call fails fast. Asking for a format by name —
toString("yaml"),toBinary("cbor"),new Tree(s, "yaml")— when no adapter is registered prints a hint about the Maven dependency to add and then throws anIllegalArgumentException. It does not silently produce JSON. To branch on availability instead of catching the exception, check first:if (TreeWriterRegistry.isAvailable("yaml")) { String yaml = node.toString("yaml"); }(
io.datatree.dom.TreeReaderRegistry.isAvailable(format)does the same for parsing.) The extension-based auto-detection used by theFile/URLconstructors andwriteTo(String)is the one exception: an unknown or unavailable extension falls back to JSON rather than throwing.