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.

About Jackson ObjectMapper
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.

How fields are matched
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`

Json string to object array
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
——————-

Java object to json string
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.