druvu-lib-json

Build JSON fluently, parse it strictly — over Gson or Jackson, and the same API over YAML.

Numbers stay exact, nothing is coerced, and every error says where it happened. Published to GitHub Packages, which needs a one-time token to read — see Install.

View on GitHub


Try it

Building:

String json = Json.object()
    .add("prop1", "1")
    .add("prop2", 2)
    .addObject("prop5").add("np1", 4).end()
    .addArray("prop6").add("ae1").add("ae2").end()
    .toJson();
// {"prop1":"1","prop2":2,"prop5":{"np1":4},"prop6":["ae1","ae2"]}

Nesting with a body — no end() to misplace:

String json = Json.object()
    .add("jsonrpc", "2.0")
    .addObject("error", e -> e.add("code", -32601).add("message", "Method not found"))
    .toJson();

Parsing:

JsonObject root = Json.parse(payload).asObject();

String id        = root.string("id");
boolean active   = root.bool("active");
BigDecimal total = root.decimal("total");
long sequence    = root.longValue("sequence");

for (JsonValue item : root.array("items")) {
    JsonObject o = item.asObject();
    // ...
}

YAML, same tree, different front door:

String config = Yaml.object()
    .add("endpoint", url)
    .addArray("profiles").add("sandbox").add("prod").end()
    .toJson();

JsonObject parsed = Yaml.parse(config).asObject();

What you get

  • one API, your choice of engine: druvu-lib-json-gson, druvu-lib-json-jackson (Jackson 3) or druvu-lib-json-yaml (YAML 1.2). The backend is discovered on the class path; your application brings its own Gson or Jackson version.
  • strict accessors. Asking a string for a number throws, with the path: Expected NUMBER but found STRING at $.items[0].name. A missing key lists the keys that are there.
  • numbers as BigDecimal, exactly as they came off the wire. asInt() and asLong() succeed only when exact. There is no double accessor.
  • a null on the wire reads as “not given”: find(key) is empty for a missing key and for a null one. The write side refuses null. Omit what you do not have.
  • strict RFC 8259 parsing, and a sealed value hierarchy that pattern-matches exhaustively.
  • build() returns what parse returns, so a built tree is navigable without serializing, and a parsed fragment grafts into a builder.
  • three ways to write (since 1.1.0): the chain for flat shapes, a lambda body for deeper or conditional nesting, and Json.fill — the JSON itself with ? placeholders, bound in order, each value serialized by the backend, then parsed strictly. Optional members read typed: findString(key) and friends return an Optional, string(key, fallback) answers absence.
  • YAML 1.2 core schema only: yes is a string, 1:30 is a string, 1_000 is a string. YAML is chosen at the call site, not discovered, so it sits next to a JSON backend without shadowing it.

What it refuses

  • two JSON backends on one class path — discovery fails, naming both
  • values and builders from different backends mixed together
  • malformed documents, trailing content, single quotes, unquoted keys
  • YAML 1.1 spellings, mapping keys that are not scalars, and .inf or .nan read as a number

Install (GitHub Packages)

GitHub Packages needs Maven authentication even for a public package. Once per machine: a classic token with the single read:packages scope (this link pre-selects it; fine-grained tokens are refused with an unexplained 401), and a server entry in ~/.m2/settings.xml:

<servers>
  <server>
    <id>github</id>
    <username>YOUR_GITHUB_USERNAME</username>
    <password>YOUR_GITHUB_TOKEN</password>
  </server>
</servers>

Then in the project, the repository and one backend. The api comes with it.

<repositories>
    <repository>
        <id>github</id>
        <url>https://maven.pkg.github.com/DenissLarka/druvu-lib-json</url>
    </repository>
</repositories>
<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-json-gson</artifactId>
    <version>1.1.0</version>
</dependency>
<!-- or druvu-lib-json-jackson, or druvu-lib-json-yaml -->

Java 25 or newer. Writing a backend of your own: the contract suite ships as the api’s tests artifact, and the README has the steps.


Where it comes from

The builder DSL began as Bryn Cooke’s fluent-json. This library detached it from Gson behind a small backend SPI and added the parsing side.


Something it almost does?

Open an issue, or write to me. If it is small and useful to more than you, I will often just build it.

Apache License 2.0. Original fluent-json Copyright 2013 Bryn Cooke.


Back to top

Copyright © 2026 druvu.com. All rights reserved.

This site uses Just the Docs, a documentation theme for Jekyll.