Processing model: Data Binding
Of 3 major processing modes that Jackson supports, data binding is often the most convenient one to use, as it allows for seamless conversion between JSON data and Java objects. It is similar to Tree Model in that JSON content is first converted to Java objects; but instead of using node-based model, regular Java objects are used.
Data binding is built using Streaming API as the underlying JSON reading/writing system: as such it has high-performance (compared to most other Java data binding libraries), but has some additional overhead compared to pure streaming/incremental processing. Generally data binding overhead is lower than actual JSON parsing/writing overhead, however.
There are 2 main "flavors" of data binding:
- Simple data binding that only uses standard JDK container types (List, Maps) and scalar types (String, Boolean, Number, nulls).
- Full data binding that can use full range of Java types including "POJOs" (Plain Old Java Objects) such as Java Beans.
Both are used via all-powerful ObjectMapper object.
Serialization
There is no real difference between flavors when serializing Java objects -- differences only matter when reading JSON and mapping (binding) it to Java objects. So serialization is achieved by:
ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(dst, myBean); // where 'dst' can be File, OutputStream or Writer
Full Data Binding
When using full data binding, deserialization type must be fully specified as something other than Object.class. For example:
MyBean value = mapper.readValue(src, MyBean.class); // 'src' can be File, InputStream, Reader, String
The main complication is handling of Generic types: if they are used, one has to use TypeReference object, to work around Java Type Erasure:
MyType<String> genValue = mapper.readValue(src, new TypeReference<MyType<String>>() { });(why? Because that is one of limited number of ways of passing full type information; mechanism called "Supertype Token")
"Simple" Data Binding
As mentioned above, Simple here just means that range of value types is limited to core JDK types. If this is acceptable, deserialization type can be simply defined as Object.class. This can apply at root level (for calls to ObjectMapper, as well as at lower level -- whatever value are declared to be of basic Object type will use Simple data binding. So something like:
Object root = mapper.readValue(src, Object.class); Map<?,?> rootAsMap = mapper.readValue(src, Map.class);
Also please note that to enable generic type information (like "Map<String,Object>"), you have to use TypeReference container as explained above.
Types used for Simple data binding are:
JSON Type |
Java Type |
object |
LinkedHashMap<String,Object> |
array |
ArrayList<Object> |
string |
String |
number (no fraction) |
Integer, Long or BigInteger (smallest applicable) |
number (fraction) |
Double (configurable to use BigDecimal) |
true|false |
Boolean |
null |
null |
where JSON type refers to JSON data types, and "Java Type" to JDK type that such constructs will be mapped to, with Simple data binding.
Configuring
SerializationConfig.Feature on/off features can be used to customize data binding to Java objects.
DeserializationConfig.Feature on/off features can be used to customize data binding to Java objects.
