Skip to content

Java sample

This independent, standard-library-only sample requires JDK 17 or later. It implements the current format syntax, common string decoding and an incremental visitor. Type expressions remain opaque; this sample supplies no type profile or typed retrieval.

From the repository root, Java source-file mode runs the CLI without a build:

Terminal window
java implementations/java/DotReg.java --mode strings examples/sample.dotreg
java implementations/java/DotReg.java --mode raw < settings.reg

For repeated runs, compile once to a separate output directory:

Terminal window
javac -encoding UTF-8 -d /tmp/dotreg-java implementations/java/DotReg.java implementations/java/DotRegTest.java
java -ea -cp /tmp/dotreg-java DotRegTest
java -cp /tmp/dotreg-java DotReg --mode strings examples/sample.dotreg

Use a suitable temporary output path on Windows. The CLI reads UTF-8 bytes from standard input when no filename is supplied. It emits one JSON array only after the entire parse and requested common decoding succeed. --mode strings (the default) adds decoded to each value; --mode raw retains undecoded right-hand sides. Headings remain separate entries. Failure means a non-zero exit status, empty standard output and a safe diagnostic on standard error. Diagnostics do not include right-hand sides, filenames or underlying input error strings.

try (var source = java.nio.file.Files.newInputStream(java.nio.file.Path.of("settings.reg"))) {
DotReg.parseEach(source, entry -> {
if (entry.kind().equals("value")) {
String value = DotReg.decodeString(entry);
// Consume this occurrence here. Return false to stop successfully.
}
return true;
});
}

parse(InputStream) returns a list or throws without returning partial results. parseEach(InputStream, Visitor) delivers complete entries in source order, including headings and repeated identical values. A visitor exception passes through unchanged before the next entry is parsed. Returning false stops successfully. Visitor side effects already performed are the application’s responsibility. Each call starts with fresh scopes, rejects missing sources and visitors and leaves its input stream open.

Entry.path() retains decoded element boundaries, empty names and dots within names. Its list is detached from the persistent heading nodes; mutation cannot change later resolution. decodeString(entry) returns the common decoded string, with entry.unset() distinguishing unset from explicit empty values. Annotations do not bypass common decoding.

DotReg.appendValue, DotReg.setText and DotReg.setTextAt edit a valid source string while preserving unrelated text. Appending follows the deepest existing matching heading with two more spaces and a relative key; with no matching heading it uses a fully qualified key at end of file. setText replaces a unique occurrence or appends when absent; setTextAt selects a zero-based repeated occurrence. Set values use escaped, double-quoted single-line syntax. The helpers do not perform type conversion or define canonical notation.

The visitor retains an 8 KiB byte buffer, active heading suffixes, the current physical line and, when necessary, a block body plus one boundary line. Lines within the buffer borrow a byte slice until their next read; spanning lines use an append buffer without an additional final byte-array copy. BOM and line-ending removal adjust offsets rather than copying line bytes. Each parse reuses one strict UTF-8 decoder. UTF-8 and LF/CRLF are validated per physical line. A non-body lookahead line is validated only after the preceding visitor succeeds. Original internal LF and CRLF are retained in blocks. Persistent parent nodes avoid storing every full ancestor path at each depth; materialising a delivered path still costs its number of elements. StringBuilder assembles block text and decoded escapes.

The format imposes no fixed size or depth limit. A long individual line or block needs memory proportional to its content; total use remains subject to the JVM’s heap and array limits. Use the visitor to avoid retaining all occurrences. The collecting API and JSON CLI deliberately retain the complete result.