Jackson ObjectMapper
This article is a guide to ObjectMapper
class from Jackson library and how it is used to convert a json string to java object and a java object to a json string.
ObjectMapper
class belongs to Jackson library and it belongs to com.fasterxml.jackson.databind
package. It is used
1. To read a json string and convert it to java object(POJO). This json string can be a java string variable, from an input stream, file etc.
2. To convert a java object(POJO) to json string.
Java docs for ObjectMapper
state,
ObjectMapper provides functionality for reading and writing JSON, either to and from basic POJOs (Plain Old Java Objects).
To use ObjectMapper
, we need to create its object using no-arg constructor as shown below
Jackson library can be added to a project using below dependencies as per the build tool.
Maven
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.13.0</version> </dependency>
Gradle
implementation 'com.fasterxml.jackson.core:jackson-core:2.13.0'
JSON to Java object
ObjectMapper
is used to convert a json string to java object. It has a readValue()
method which takes two arguments:
1. Json string which needs to be converted to java object.
2. Class type of java object.
Converting a json string to java object is also referred to as deserialization.
Example,
Below is a class that we will be using for json string to java object conversion
package com.codippa; public class Laptop { private String brand; private String model; // getter and setter }
And following is the code to convert a json string to java object using ObjectMapper
ObjectMapper mapper = new ObjectMapper(); String json = "{\"brand\":\"Abc\", \"model\":\"XYZ\"}"; try { Laptop l = mapper.readValue(json, Laptop.class); System.out.println("Brand:"+l.getBrand()); System.out.println("Model:"+l.getModel()); } catch (JsonMappingException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); }
Output of this code is
Brand: Abc
Model: XYZ
readValue()
can accept source json from various sources such as inputstream, file, url etc. There are following overloaded methods for the same.
public T readValue(String content, Class<T> valueType) public T readValue(File content, Class<T> valueType) public T readValue(Reader content, Class<T> valueType) public T readValue(URL content, Class<T> valueType) public T readValue(DataInput content, Class<T> valueType)
Remember that all these sources should contain a valid JSON for ObjectMapper to convert it to java object.
ObjectMapper
maps the keys of json string to the fields or instance variables of a java object and populates their values. Following are the requirements for a class so that the fields of its objects are mapped to json string correctly.
1. It should have a no-arg or default constructor.
2. Field names should match the names of keys of json string. Names of their getter methods should match with the field names after removing get prefix.
Example, getter method for field age
should be getAge()
.
3. Case of class fields and json string keys should also match.
Ignoring properties
There should be a matching field in java class for every key in json string.
If there is a key in json string, for which there is no matching property in java class, then readValue()
will raise an error.
Thus, if the json string is
{ "company":"Abc", "model": "XYZ" }
readValue()
will raise below exception
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field “company” (class com.codippa.Laptop), not marked as ignorable
This is because there is no field company
in the java class but there is a key with this name in json string.
To resolve this problem, mark the java class with @JsonIgnoreProperties
as shown below.
@JsonIgnoreProperties(ignoreUnknown = true) public class Laptop { // code }
With this annotation in place, ObjectMapper
will ignore any keys in json string that are not present in java class.
If you do not want to use annotations over the class for any reason, there is another way using configure()
method of ObjectMapper
as below.
mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
This configures ObjectMapper
to continue even if there are some additional properties in json string.
Primitive value conversion
If the java class contains a field of primitive type and the json string contains a null
value for the corresponding key, then ObjectMapper
sets the default value as per data type.
That is, if the java class contains below property
public class Laptop { private String brand; private String model; private int ram; }
Then, below json string will set the value of ram
to 0
{ "brand":"Abc", "model": "XYZ", "ram": null }
If you want that the conversion of json string to java object should fail, in case of null
value for a primitive property, then configure ObjectMapper
as
mapper.configure( DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
With this configuration, ObjectMapper
will fail, if any primitive type has a null
value in json string.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot map `null` into type `int`
Suppose you have a json string that contains a json array and it needs to be converted to an array of java objects.
ObjectMapper
can be used to convert json string to a java array of objects as shown below ObjectMapper mapper = new ObjectMapper(); String json = "[{\"brand\":\"Abc\", \"model\":\"XYZ\"}," + "{\"brand\":\"Def\", \"model\":\"123\"}]"; try { Laptop[] arr = mapper.readValue(json, Laptop[].class); // iterate over array for(Laptop l : arr) { System.out.println("Brand:" + l.getBrand()); System.out.println("Model:" + l.getModel()); System.out.println("----------------"); } } catch (JsonMappingException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); }
Note the second argument to readValue()
is of type array of class objects.
Output is
Brand:Abc
Model:XYZ
—————-
Brand:Def
Model:123
—————-
Json string to java list
A json string which has multiple json objects can also be converted to a list of java objects.
For this, we need to pass an object of Jackson’s TypeReference
class with its generic type as the type of object to which we want to convert.
In this case, this type will be java.util.List
. Example,
ObjectMapper mapper = new ObjectMapper(); String json = "[{\"brand\":\"Abc\", \"model\":\"XYZ\"}," + "{\"brand\":\"Def\", \"model\":\"123\"}]"; try { // convert to list List<Laptop> arr = mapper.readValue(json, new TypeReference<List<Laptop>>(){}); // iterate over array for(Laptop l : arr) { System.out.println("Brand:" + l.getBrand()); System.out.println("Model:" + l.getModel()); System.out.println("----------------"); } } catch (JsonMappingException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); }
com.fasterxml.jackson.core.type.TypeReference
is an abstract class. So, we need to pass its implementation to readValue()
.
Json string to java map
A java map is a data structure having key-value pairs as its entries. ObjectMapper
can convert a json string to a map directly using its readValue()
method.
Json string should also be in key-value format. Key of each json entry will become the key of map and value of json key will be its value.
Since map is a java type, we need to use TypeReference
with Map
type as the second argument to readValue()
.
Example,
ObjectMapper mapper = new ObjectMapper(); String json = "{\"brand\":\"Abc\",\"model\":\"XYZ\",\"size\":\"12\"}]"; try { Map<String, String> map = mapper.readValue(json, new TypeReference<Map<String,String>>() {}); map.keySet().forEach(key -> { System.out.println("Key: "+key); System.out.println("Value: "+map.get(key)); System.out.println("-------------------"); }); } catch (JsonMappingException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); }
Once ObjectMapper
creates a java map from json string, we can iterate over the map to print its keys and values.
Output is
Key: brand
Value: Abc
——————-
Key: model
Value: XYZ
——————-
Key: size
Value: 12
——————-
ObjectMapper
can also be used to convert a java object to a json string using its writeValue()
method.All the fields of the object become the keys and their values become the value of these keys. Example,
ObjectMapper mapper = new ObjectMapper(); Laptop l = new Laptop("Abc", "Xyz"); StringWriter w =new StringWriter(); try { mapper.writeValue(w, l); String json = w.toString(); System.out.println("Json string is:"); System.out.println(json); } catch (JsonMappingException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); }
Output is
{“brand”:”Abc”,”model”:”Xyz”}
Object fields which are not initialized are set to default values according to their data types.
ObjectMapper Date Handling
If there is field in java class, which is of type java.util.Date
, then while converting object to json string, ObjectMapper
converts its value to a long value, which is equal to the number of milliseconds since January 1, 1970(also known as epoch).
Suppose our java class has a field of type Date
as below
public class Laptop { private String brand; private String model; private Date purchaseDate; }
And below is the conversion of its object to json string
ObjectMapper mapper = new ObjectMapper(); Laptop l = new Laptop("Abc", "Xyz"); l.setPurchaseDate(new Date()); StringWriter writer = new StringWriter(); try { mapper.writeValue(writer, l); System.out.println(writer.toString()); } catch (IOException e) { e.printStackTrace(); }
This will be the output
{“brand”:”Abc”,”model”:”Xyz”,”purchaseDate”:1636002108319}
This value of date does not make any sense.
Jackson ObjectMapper
provides an option to set the date in required and meaningful format in json string.
It has a setDateFormat()
method, which takes an object of DateFormat
with the format of dates. ObjectMapper will automatically format any dates while converting a java object to json string and vice-versa.
Documentation of setFormat()
method states,
Method for configuring the default DateFormat to use when serializing time values as Strings, and deserializing from JSON Strings
Below is the usage example,
ObjectMapper mapper = new ObjectMapper(); Laptop l = new Laptop("Abc", "Xyz"); l.setPurchaseDate(new Date()); StringWriter writer = new StringWriter(); try { mapper.setDateFormat(new SimpleDateFormat("dd/MM/yyyy")); mapper.writeValue(writer, l); System.out.println(writer.toString()); } catch (IOException e) { e.printStackTrace(); }
Output will be
{“brand”:”Abc”,”model”:”Xyz”,”purchaseDate”:”04/11/2021″}
You can see that the date is now formatted instead of a long value.
Spring boot configuration
Spring boot by default uses Jackson ObjectMapper for object to json conversion when sending response and creating a java object from json string while receiving request.
When you create a spring boot project and add spring boot web starter dependency, it automatically adds Jackson library to the classpath.
This means that for converting json string to java objects and vice-versa, it uses ObjectMapper
internally.
That is all on Jackson ObjectMapper tutorial. Now, you can easily convert a json string to java object automatically and convert a java object to a valid json string.