json

BFO JSON/CBOR Parser

The BFO JSON/CBOR/Msgpack Parser is yet another Java JSON parser, with the follow emphasis:

simple

fast

correct

self-contained

Features

Building and Documentation

Design Decisions

Examples

// The basics
Json json = Json.read("{}"}; // Create a new map
json.put("a", "apples"); // Add a string
json.put("b.c", new Json("oranges")); // Add an intermediate map and another string
json.put("b.c[1]", 3}; // Replace previous string with an array, add a null then a number.
json.put("\"d.e\"", true); // Add a key containing a quote character
System.out.println(json); // {"a":"apples","b":{"c":[null,3]},"d.e":true}
json.write(System.out, null); // The same as above, but doesn't serialize to a String first.
System.out.println(json.get("b.c[1]").stringValue()); // "3"
System.out.println(json.get("b.c[1]").intValue()); // 3
System.out.println(json.get("b").get("c").get(1).intValue()); // 3

// Types
json.put("d", "2");
json.put("e", 0);
System.out.println(json.type()); // "map"
System.out.println(json.isMap()); // true
System.out.println(json.get("d")); // "2"
System.out.println(json.get("d").type()); // "string"
System.out.println(json.get("d").intValue()); // 2 (automatically converted from string)
System.out.println(json.get("d").numberValue().getClass()); // java.lang.Integer
json.put("d", "9999999999");
System.out.println(json.get("d").numberValue().getClass()); // java.lang.Long
json.put("d", "99999999999999999999999999");
System.out.println(json.get("d").numberValue().getClass()); // java.math.BigInteger
System.out.println(json.get("d").booleanValue()); // true
System.out.println(json.get("e").booleanValue()); // false
json.put("e", Json.read("[]")); // Add a new list
System.out.println(json.get("e").type()); // "list"
json.put("e[0]", false);
System.out.println(json.get("e")); // [false] - e is a list
json.put("e[\"a\"]", true); // this will convert e to a map
System.out.println(json.get("e")); // {"0":false,"a":true}
json.setValue(new Json("string")); // copy value from specified object
System.out.println(json.value()); // "string"

// Serialization
json = Json.read("{b:1, a: 2}");  // Fails, keys is not quoted
json = Json.read(new StringReader("{b: 1, a: 2}"), new JsonReadOptions().setAllowUnquotedKey(true)); // OK
json.write(System.out, new JsonWriteOptions().setPretty(true).setSorted(true)); // pretty print and sort keys
// {
//   "a": 2,
//   "b": 1,
// }

// CBOR / Msgpack
json.put("buffer", ByteBuffer.wrap(new byte[] { ... }));   // add a ByteBuffer
System.out.println(json.get("buffer").type());      // "buffer"
System.out.println(json.get("buffer").stringValue());  // Base64 encoded value of buffer
json.setTag(20);        // Set a CBOR tag on a value
json.writeCbor(new OutputStream(...), null);    // serialize the same JSON object to CBOR
json = Json.readCbor(new InputStream(...), null);   // read CBOR from an Inputream
System.out.println(json.get("buffer").getTag());        // "20"
System.out.println(json.get("b").getTag());        // "-1", which means no tag
json.put("nan", Double.NaN);
json.writeCbor(new OutputStream(...), null);    // infinity is fine in CBOR
json.write(new StringWriter(), null);    // throws IOException - infinity not allowed in Json
json.write(new StringWriter(), new JsonWriteOptions().setAllowNaN(true));  // infinity serializes as null
json.writeMsgpack(new OutputStream(...), null);    // Msgpack instead of CBOR


// Events
json.addListener(new JsonListener() {
    public void jsonEvent(Json root, JsonEvent event) {
        if (event.after == null) {
            System.out.println("Removed " + root.find(event.before));
        } else if (event.before == null) {
            System.out.println("Added " + root.find(event.after));
        } else {
            System.out.println("Changed " + root.find(event.after) + " from " + event.before+" to " + event.after);
        }
    }
});
json.put("a.b", true);  // "Added a.b"
json.get("a.b").put("c", true);  // "Added a.b.c"
json.get("a.b").put("c", false);  // "Changed a.b.c" from true to false
json.remove("a.b"); // "Removed a.b"

// JsonPath
json = Json.parse("{\"a\":{\"b\":{\"c\":[10,20,30,40]}}}");
json.eval("$..c[2]").intValue(); // 30

In addition the JWT class adds basic support for Java Web Tokens. With only a handful of methods it is trivial to use, but supports all JWT signing methods. Encryption with JWE is not supported

JWT jwt = new JWT(Json.parse("{\"iss\":\"foo\"}"));
byte[] key = ...
jwt.sign(key, "HS256");           // Sign using a symmetric key
jwt = new JWT(jwt.toString());    // Encode then decode
assert jwt.verify(key, null);     // Verify using the same symmetric key

byte[] pubkey = ...
byte[] prikey = ...
jwt.getHeader().put("x5u", ...);     // Add custom content to header
jwt.sign(prikey, "ES256");           // Sign using a asymmetric key
assert jwt.verify(pubkey, "ES256");  // Verify using corresponding key
PublicKey pubkeyobj = ...
assert jwt.verify(pubkeyobj, "ES256", null); // or use a java.security.Key

jwt.getPayload().clear();            // Modify the payload
assert !jwt.verify(pubkey, "ES256"); // Signature is no longer valid

This code is written by the team at bfo.com. If you like it, come and see what else we do.