JSON SERDE (SerializerDeserializer) ![Build Status](https://camo.githubusercontent.com/675a07352c4315bbb43a44b5c010f9248c1134ffd31c8cc61ffd5a1483a99c71/68747470733a2f2f7472617669732d63692e636f6d2f616e726f7363612f6a736f6e2d73657264652e7376673f6272616e63683d6d6173746572)
A lightweight JSON serialization & deserialization library. It's a thin wrapper around Jackson. A small inconvenience of Jackson is that the DTO which is serialized/deserialized to/from JSON either has to have a default constructor and getters/setters for every field or the DTO has to have a constructor annotated with @JsonCreator
. There are rare use-cases when you want to serialize/deserialize an object from a third-party library, when the DTO doesn't have getters/setters for every field, nor a default constructor. This makes Jackson unusable for such use-cases. JSON SERDE doesn't rely on getters/setter but works with fields directly. Upon deserialization JSON SERDE instantiates objects without invoking their constructors (using Objenesis). Apart from that, Jackson can't handle object graphs with circular dependencies. JSON SERDE can handle such object graphs.
Maven
<dependency>
<groupId>com.github.anrosca</groupId>
<artifactId>json-serde</artifactId>
<version>0.0.1</version>
</dependency>
Examples
Let's say we have the following DTO (with no getters & setters):
public static class StringDummy {
private final String firstName;
private final String lastName;
public StringDummy(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
//...
}
You can serialize it to JSON just like that:
import inc.evil.serde.JsonMapper;
public class JsonSerdeDemo {
public static void main(String[] args) {
JsonMapper jsonMapper = new JsonMapper();
StringDummy dto = new StringDummy("Mike", "Smith");
String json = jsonMapper.serialize(dto);
}
}
The json String would look like this:
{
"targetClass" : "inc.evil.serde.StringDummy",
"state" : {
"firstName" : {
"type" : "java.lang.String",
"value" : "Mike"
},
"lastName" : {
"type" : "java.lang.String",
"value" : "Smith"
}
},
"__id": 1
}
From the JSON sample above, it's clear that along with the object state, the resulting JSON has some metadata like field types. The __id
field from JSON is an unique object id generated by JSON SERDE which is useful when you have circular object dependencies. The deserialization process is also straightforward. You can deserialize it like this:
import inc.evil.serde.JsonMapper;
public class JsonSerdeDemo {
public static void main(String[] args) {
JsonMapper jsonMapper = new JsonMapper();
String json = ""; //the JSON representation of the object
StringDummy dto = jsonMapper.deserialize(json, StringDummy.class);
}
}
Circular object dependencies
Let's say you have an object graph with circular dependencies, like this:
public class Foo {
private final int age;
private final Bar bar;
public Foo(int age, Bar bar) {
this.age = age;
this.bar = bar;
}
//...
}
public class Bar {
private final String name;
private Foo foo;
public Bar(String name) {
this.name = name;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
//...
}
When you serialize an instance of Foo class to JSON, the JSON representation will look like this:
public class CircularDependenciesDemo {
public static void main(Stringp[] args) {
Bar bar = new Bar("Mike");
Foo foo = new Foo(42, bar);
bar.setFoo(foo);
JsonMapper jsonMapper = new JsonMapper();
String json = jsonMapper.serialize(foo);
}
}
{
"targetClass": "inc.evil.serde.Foo",
"state": {
"bar": {
"type": "inc.evil.serde.Bar",
"value": {
"targetClass": "inc.evil.serde.Foo",
"state": {
"foo": {
"type": "inc.evil.serde.Foo",
"value": {"type": "__ref", "value": "1"}
},
"name": {"type": "java.lang.String", "value": "Mike"}
},
"__id": 2
}
},
"age": 42
},
"__id": 1
}
You can see from the JSON above that the value of the Bar.foo
field has the type __ref
and a value of 1
. The value of 1 is actually the object id we're referring to (object with the __id
equal to 1).
License
The JSON SERDE is released under version 2.0 of the Apache License.