Update 11 July 2011: I’ve done several commits on github since announcing the project here. New features have been added; bugs have been fixed; you can find jsonj on maven central now as well; etc. In short, head over to github for the latest on this.
I’ve just uploaded a weekend project to github. So, here it is, jsonj. Enjoy.
If you read my post on json a few weeks ago, you may have guessed that I’m not entirely happy with the state of json in Java relative to other languages that come with native support for json. I can’t fix that entirely but I felt I could do a better job than most other frameworks I’ve been exposed to.
So, I sat down on Sunday and started pushing this idea of just taking the Collections framework and combining that with the design of the Json classes in GSon, which I use at work currently, and throwing in some useful ideas that I’ve applied at work. The result is a nice, compact little framework that does most of what I need it to do. I will probably add a few more features to it and expand some of the existing ones. I use some static methods at work that I can probably do in a much nicer way in this framework.
Here is some example usage (note, this will likely not stay in sync with the code in github, check there for latest version):
Updated to version 0.3, check here for latest version
/**
* Copyright (c) 2011, Jilles van Gurp
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.jsonj;
import static org.jsonj.tools.JsonBuilder.array;
import static org.jsonj.tools.JsonBuilder.nullValue;
import static org.jsonj.tools.JsonBuilder.object;
import static org.jsonj.tools.JsonBuilder.primitive;
import static org.jsonj.tools.JsonSerializer.serialize;
import static org.jsonj.tools.JsonSerializer.write;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import org.jsonj.tools.JsonParser;
import org.testng.annotations.Test;
/**
* Not really a test but a nice place to show off some how to use this.
*/
@Test
public class ShowOffTheFramework {
/** this could be a singleton or a spring injected object, threadsafe of course. */
private final JsonParser jsonParser = new JsonParser();;
public void whatCanThisBabyDo() throws IOException {
= object()
JsonObject object .put("its", "just a hash map")
.put("and", array(
primitive("adding"),
primitive("stuff"),
object().put("is", "easy").get(),
array("another array")))
.put("numbers", 42)
.put("including_this_one", 42.0)
.put("booleanstoo", true)
.put("nulls_if_you_insist", nullValue())
.put("a", object().put("b", object().put("c", true).put("d", 42).put("e", "hi!").get()).get())
.put("array",
array("1", "2", "etc", "varargs are nice")).get();
assertTrue(object instanceof LinkedHashMap, "JsonObject actually extends LinkedHashMap");
// get with varargs, a natural evolution for Map
assertTrue(object.get("a","b","c").asPrimitive().asBoolean(), "extract stuff from a nested object");
assertTrue(object.getBoolean("a","b","c"), "or like this");
assertTrue(object.getInt("a","b","d") == 42, "or an integer");
assertTrue(object.getString("a","b","e").equals("hi!"), "or a string");
assertTrue(object.getArray("array").isArray(), "works for arrays as well");
assertTrue(object.getObject("a","b").isObject(), "and objects");
// builders are nice, but still feels kind of repetitive
= object.getOrCreateObject("1","2","3","4");
JsonObject anotherObject .put("5", "xxx");
anotherObjectassertTrue(object.getString("1","2","3","4","5").equals("xxx"),"yep, we just added a string value 5 levels deep");
= object.getOrCreateArray("5","4","3","2","1");
JsonArray anotherArray .add("xxx");
anotherArrayassertTrue(object.getArray("5","4","3","2","1").contains("xxx"),"naturally works for arrays too");
// Lets do some other stuff
assertTrue(object.equals(object),
"equals is implemented as a deep equals");
assertTrue(array("a", "b").equals(array("b", "a")),
"mostly you shouldn't care about the order of stuff in json");
assertTrue(
object().put("a", 1).put("b", 2).get()
.equals(
object().put("b", 2).put("a", 1).get()),
"true for objects as well");
// Arrays are lists
= array("foo", "bar");
JsonArray array assertTrue(array instanceof LinkedList, "JsonArray extends LinkedList");
assertTrue(array.get(1) == array.get("bar"), "returns the same object");
assertTrue(array.contains("foo"), "obviously");
assertTrue(array.contains(primitive("foo")), "but this works as well");
// serialize like this
String serialized = serialize(object);
// parse it
= jsonParser.parse(serialized);
JsonElement json
// and write it straight to some stream
write(System.out, json, false);
// or pretty print it like this
System.out.println("\n" + serialize(json, true));
}
}