Java json – jackson List serialization

Also see json simple org.json

In this tutorial we will see how to convert a java List to JSON. Serializing list is a little tricky since by default the type info is not stored while serializing and deserializing lists. In this tutorial we look at two examples. In the first example we serialize an Object that has a java List as one of its properties. In the second example we try and serialize the List directly. In both examples we use special configuration to preserve type info.

Example 1 : Serializing Object containing a list

The example converts a Zoo class to json. the zoo class contains the name of zoo, its city and a list of animals. The list is of type ‘Animal’, i.e. the list contains elements that are subclass of the Abstract class Animal. Lets see what happens when we try to serialize zoo. First we create the Zoo class. Notice how the constructor looks. When we try to get the Zoo Object back from the JSON, Jackson has to know that it should create the Zoo Object using the constructor that takes in the name and city properties.

class Zoo {
	public String name;
	public String city;

	
	@JsonCreator
	public Zoo(@JsonProperty("name") String name,@JsonProperty("city") String city) {
		this.name = name;
		this.city = city;
	}

	public List<Animal> animals = new ArrayList<Animal>();

	public List<Animal> addAnimal(Animal animal) {
		animals.add(animal);
		return animals;
	}

}

The Animal is an abstract class. It is further extended to create the Elephant and the Lion class.

class Elephant extends Animal {

	@JsonCreator
	public Elephant(@JsonProperty("name") String name) {
		super.name = name;
	}

	@Override
	public String toString() {
		return "Elephant : " + name;
	}
}

class Lion extends Animal {
	@JsonCreator
	public Lion(@JsonProperty("name") String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Lion: " + name;
	}
}

Lets now create a serializer for Zoo. Imagine that the London zoo needs to shift to a larger area. We will have to serialize the zoo from its current location and deserialize it at the target location. (a teleportation machine)

We use the ObjectMapper class to do the serialization and print the json to console. You could also print it to a file

package com.studytrails.json.jackson;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SerializeZoo {
	public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
         Zoo zoo = new Zoo("London Zoo", "London");
         Lion lion = new Lion("Simba");
         Elephant elephant = new Elephant("Manny");
         zoo.addAnimal(elephant).add(lion);
         ObjectMapper mapper = new ObjectMapper();
         mapper.writeValue(System.out, zoo);
	}
}

Ok so lets see how our zoo looks like. Remember, we should be able to re create the zoo (along with all its animals) when we deserialize it

{"name":"London Zoo","city":"London","animals":[{"name":"Manny"},{"name":"Simba"}]}

Clearly our teleporter is not ready. Manny and Simba are in there, but there is nothing in the json that says that Manny is an elephant and Simba is a lion. Lets see what happens when we try to deserialize the zoo

package com.studytrails.json.jackson;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DeserializeZoo {

	public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
		String json = "{\"name\":\"London Zoo\",\"city\":\"London\"," + "\"animals\":[{\"name\":\"Manny\"},{\"name\":\"Simba\"}]}";
		ObjectMapper mapper = new ObjectMapper();
		mapper.readValue(json, Zoo.class);
	}
}

We get an error! the error says “Can not construct instance of com.studytrails.json.jackson.Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information” . Ok, we were expecting this. Lets see how to resolve it. We need to be able to put the information about the type in the json. There are two things you need to do this 1. Tell Jackson that we need to include the type info for Animal class.

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")

2. Tell Jackson that Animal can have subclasses Elephant and Lion

@JsonSubTypes({ @Type(value = Lion.class, name = "lion"), @Type(value = Elephant.class, name = "elephant") })

Lets see how our json looks now

{"name":"London Zoo","city":"London",
"animals":[{"@class":"com.studytrails.json.jackson.Elephant","name":"Manny"},
           {"@class":"com.studytrails.json.jackson.Lion","name":"Simba"}]}

This looks much better. Now, if you read the json back using the Zoo class then it works well and the Zoo class would have a list of animals.

Example 2 : Serializing a list

In the previous example we saw how to serialize a class that has a List. In this example lets see how to serialize a list directly. We will use the same Animal, Lion and Elephant classes. Lets see what happens when we try to serialize the list directly (note that we have added the typeinfo annotations to the Animal class)

public class SerializeAnimals {
	public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
		List animals = new ArrayList();
		Lion lion = new Lion("Samba");
		Elephant elephant = new Elephant("Manny");
		animals.add(lion);
		animals.add(elephant);
		ObjectMapper mapper = new ObjectMapper();

		mapper.writeValue(System.out, animals);
	}
}	




This gives the following json

[{"name":"Samba"},{"name":"Manny"}]

No type info! To add type info while serializing Lists directly you need to configure the mapper in this way

mapper.writerWithType(new TypeReference<List
		<Animal>>() {
		}).writeValue(System.out, animals);

This now produces the correct json

[{"@class":"com.studytrails.json.jackson.Lion","name":"Samba"},
{"@class":"com.studytrails.json.jackson.Elephant","name":"Manny"}]

So to recap, in this tutorial we saw how to i. serialize a Java object containing a List and ii. serialize a list (root object)

2 thoughts on “Java json – jackson List serialization”

  1. Sadly we cannot use class names as type-strings, need to use JsonTypeInfo.Id.NAME.

    Once an object has a type-string, you can serialize it directly and see the typestring: e.g. {“type”:”elephant”,”name”:”Manny”}. Object[] ought to be exactly the same as ‘[‘ + serialize(it.next()) + ‘,’ + … ‘]’. Which produces the correct result! There’s no real excuse for a serialized array of Objects being anything except an array of serialized objects separated by ‘,’ and surrounded by ‘[]’.

    type erasure is completely irrelevant, though everyone seems obsessed with it.

    Reply

Leave a Comment