Json Serializer
Jodd Json serializer converts your objects into JSON strings.
The main class to use is JsonSerializer
. Workflow is easy:
create an instance of this class, configure it
and then we are ready to serialize objects.
You may re-use the same JsonSerializer
instance
(i.e. configuration) for more than one serialization.
Let's see more on how serialization works.
Basic usage
Create the new instance of JsonSerializer
and pass
an object we want to serialize:
JsonSerializer jsonSerializer = new JsonSerializer(); String json = jsonSerializer.serialize(object);
Thats it! JsonSerializer
process our target object according to it's
type. It recognizes arrays, lists, maps, collections, strings,
numbers etc. and returns them in correct JSON format.
If you pass an object, JsonSerializer
will scan all it's properties
(defined by getters) and create JSON map from it. Each property
of a bean will be also serialized according to it's type and so on.
Of course, JsonSerializer
detects circular dependencies
(by checking objects identity).
There is one important default behavior of JsonSerializer
:
Collections (lists, arrays…) are not serialized by default.
This plays well with some 3rd party libraries (like ORM) where collections represents lazy relationships.
Path
JSON serialization is recursive: all properties of target object
gets serialized and so on, until the simple types. During the serialization,
JsonSerializer
browse the 'object graph' of given object. Current
serialization position is determined by the path: string that
consist of dot-separated property names up to this position.
Paths are used to reference a property in object graph of a target.
For example, the path may be user.work.prefix
. This mean that we can
get it's value in Java by calling: getUser().getWork().getPrefix()
on
target object.
Deep serialization
If you want to serialize everything, don't worry! Just set the deep
flag to true
:
JsonSerializer jsonSerializer = new JsonSerializer(); String json = jsonSerializer.deep(true).serialize(object);
Object will be fully serialized now.
Filtering properties
Serialization process can be fine-tuned: properties can be included and excluded from serialization. There are several ways how this can be done.
Include/Exclude methods
By using include()
and exclude()
methods we can include
and exclude property referenced by it's path. Let's take
the following class as an example:
public class Person { private String name; private Address home; private Address work; private List<Phone> phones = new ArrayList<Phone>(); // ... and getters and setters }
If we serialize this class using default JsonSerializer
we
will get JSON map with 3 keys: name
, home
and work
.
Property phones
is not serialized by default as it is a list.
We can include phones
with the following code:
String json = new JsonSerializer .include('phones') .serialize(object);
In the same way we can exclude a property. For example:
String json = new JsonSerializer .exclude('work') .include('phones') .serialize(object);
Resulting JSON in this case would also be a map with 3 keys:
name
, home
and phones
.
Of course, you can specify deeper include/exclude paths, like:
String json = new JsonSerializer .exclude('work') .include('phones') .exclude('phones.areaCode') .serialize(object);
This time we changed how inner object (Phone
) is serialized.
Include/exclude paths can contain a wildcard (*
). Wildcard
replaces more properties at once. Wildcard can only replace whole
property names, not partial. Here is how it can be used:
String json = new JsonSerializer .exclude('*') .include('name') .serialize(object);
Resulting JSON map this time contains just one key: name
, as
all others properties are excluded.
JSON Annotation
Using include/exclude methods can be cumbersome especially if you
always intend something to be excluded or included. Json provides
a way to express this using annotation. The JSON
annotation can be used
to mark a property (getter or a field) in the object as included by default.
In above example we may say that Phones
are integral part of
a Person
and that we should always have them serialized. So
we can do the following:
public class Person { private String name; private Address home; private Address work; @JSON private List<Phone> phones = new ArrayList<Phone>(); // ... and getters and setters }
That's it! But wait, that's not all :) Json supports two ways how a class can be annotated:
-
In the default mode,
JSON
annotations simply defines additional properties that have to be included. All other properties, that are not marked with an annotation, are also included according to the rules. This mode is usually used to include collection properties, that are excluded by default. -
In the strict mode,
JSON
annotation defines only properties that have to be included. All other properties, that are not marked with an annotation, are not included, even though they should be according to the rules. Strict mode is enabled by annotating the class with the annotation and setting thestrict
element totrue
:
@JSON(strict = true) public class Person { @JSON private String name; @JSON private Address home; private Address work; @JSON private List<Phone> phones = new ArrayList<Phone>(); // ... and getters and setters }
Here property work
is not serialized as it is not annotated and the
class is serialized in strict
mode.
Furthermore, by using JSON
annotation we can change the name of
the generated key, e.g.:
public class Person { @JSON private String name; @JSON(name = "home_address") private Address home; //... }
We have changed the name of the home
property to appear as home_address
.
Excluding types
We can also exclude properties of certain type or that matches certain type name wildcard pattern. Sometimes we need to serialize complex beans that contain properties that are meaningless for the serialization, like streams. We can exclude such properties from getting serialized:
new JsonSerializer() .excludeTypes(InputStream.class) .serialize(object);
This will exclude properties that are of InputStream
type. We could also
add the following rule:
new JsonSerializer() .excludeTypes(InputStream.class) .excludeTypes("javax.*") .serialize(object);
where the whole package gets excluded.
Class name meta data
By default, JsonSerializer
does not outputs
object's class name. However, sometimes we want
to preserve the type of serialized object (especially
if we want to parse the JSON string back into object).
To do this, just enable this feature:
new JsonSerializer() .setClassMetadataName("class") .serialize(object);
Good thing is that we may pass the class key name.
JSON Type Serializers
JsonSerializer
knows to serializes common types.
This knowledge is defined in implementations of TypeJsonSerializer
.
These implementations know how to serialize certain type.
TypeJsonSerializerMap
contains default bindings between
types and theirs JSON serializers.
Of course, it is possible to add custom type serializers.
For example, we might want to change how Date
is serialized:
instead as milliseconds number, we can serialize it as a date string.
Again we have options:) We can bind custom serializer to a type,
so all Date
properties in our example will be serialized in a custom
way; or we can bind single property to custom serializer, using it's path:
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); String json = new JsonSerializer() .use("birthdate", new DateJsonSerializer() { @Override public void serialize(JsonContext jsonContext, Date date) { jsonContext.writeString(dateFormat.format(date)); } }) .serialize(foo);
Jodd Json comes with default set of type serializers that should cover all common types and needs. Hower, don't hesitate to build your own type serializer when needed.
Global configuration
In all above examples we have been configuring the JsonSerializer
instance. If we need to set up permanent changes, that would
apply on whole application, then we would use JoddJson
class instead.
This is module's class and contains defaults configuration values
for all of above settings.
Custom JSON annotation
One great thing about configuration is that it is possible to set custom JSON annotation. If you do not want to use default annotation from Jodd Json, then just create your own annotation and register it. Custom annotation may contain all or only some elements; and it may contain some custom additional data.
Power to the people!