Jackson: Java to JSON and back

Creating JSON from Java

Jackson provides classes that can be used to convert a Java Object to JSON and back. In this example we look at how to build a JSON construct from a Java Object. We will start with a simple class and gradually start adding complexities to it. Lets say that we are a music company and we want to publish an api where users can query for Album. We first build an Album class with a single property title.

class Album {
    private String title;

    public Album(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}

we use the ObjectMapper to convert the Object to JSON. By Default Jackson would use BeanSerializer to serialize the POJO. Here’s how our serializer Example looks so far. Note that the bean should have getters for private properties or the property should be public Here’s how the JSON looks

{"title":"Kind Of Blue"}

Lets add an array of links to the album (along with their getters and setters) These could be links to the press releases or album reviews.

private String[] links;

In the main method add this:

album.setLinks(new String[] { "link1", "link2" });

This is how the JSON looks now. Note that the array is converted to a JSON array. (enclosed within ‘[’ and ‘]’)

{"title":"Kind Of Blue","links":["link1","link2"]}

Next we add a List of Songs to the Album.

List<String>> Songs = new ArrayList<String>();

Add the list to the Albums Object

List<String> songs = new ArrayList<String>();
songs.add("So What");
songs.add("Flamenco Sketches");
songs.add("Freddie Freeloader");
album.setSongs(songs);

The resulting json looks like this. Note that the List is also converted to an array. You can learn more about List Serialization in this tutorial.

{"title":"Kind Of Blue","links":["link1","link2"],
"songs":["So What","Flamenco Sketches","Freddie Freeloader"]}

Next, lets add an artist to the Album. Artist is a class that contains the artist name and his birthdate represented by a Date instance. Note that Artist is an object and hence is enclosed in JSON by ‘{’ and ‘}’. These brackers are JSON representation of objects and contains key value pairs. For brevity we declare the Artist properties as public.

class Artist {
    public String name;
    public Date birthDate;
}

Lets add an Artist to the album

Artist artist = new Artist();
artist.name = "Miles Davis";
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
artist.birthDate = format.parse("26-05-1926");
album.setArtist(artist);

The JSON

{"title":"Kind Of Blue","links":["link1","link2"],
"songs":["So What","Flamenco Sketches","Freddie Freeloader"],
"artist":{"name":"Miles Davis","birthDate":-1376027600000}}

To make JSON visually more readable we add this line. Note that this should not be done for production systems, but only during testing or development since this would increase the size of the json.

mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

The JSON now looks well formatted

{
  "title" : "Kind Of Blue",
  "links" : [ "link1" , "link2" ],
  "songs" : [ "So What", "Flamenco Sketches", "Freddie Freeloader" ],
  "artist" : {
    "name" : "Miles Davis",
    "birthDate" : -1376027600000
  }
}

we now add a map of musicians and the instrument they play in the album.

private Map<String,String> musicians = new HashMap<String, String>();
public Map<String, String> getMusicians() {
        return Collections.unmodifiableMap(musicians);
}
public void addMusician(String key, String value){
        musicians.put(key, value);
}

and in the main class

album.addMusician("Miles Davis", "Trumpet, Band leader");
album.addMusician("Julian Adderley", "Alto Saxophone");
album.addMusician("Paul Chambers", "double bass");

The json

{
  "title" : "Kind Of Blue",
  "links" : [ "link1", "link2" ],
  "songs" : [ "So What", "Flamenco Sketches", "Freddie Freeloader" ],
  "artist" : {
    "name" : "Miles Davis",
    "birthDate" : -1376027600000
  },
  "musicians" : {
    "Julian Adderley" : "Alto Saxophone",
    "Paul Chambers" : "double bass",
    "Miles Davis" : "Trumpet, Band leader"
  }
}

Lets add some more features to the conversion. we first tell the mapper to arrange the Map by keys using it natural order

mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

The date has been formatted as the epoch time. Lets format it into a more human readable format

SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy");
mapper.setDateFormat(outputFormat);

By default, jackson uses the name of the java field as the name of the json property. You can change that by using annotations as explained in this tutorial. However at times you may not have access to the java bean or you do not want to bind the java bean to a Jackson annotation. In this case jackson provides a way to change the default field name. Use the setPropertyNamingStrategy method on the mapper to set the naming strategy for the field. You need to override either the the nameForField method or the nameForGetterMethod depending on whether you have public field in the bean or a getter in the bean. In our example lets change the ’title’ of the album to ‘Album-Title’ and the ’name’ of the artist to ‘Artist-Name’. Make this changes to the main method

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
@Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
   if (field.getFullName().equals("com.studytrails.json.jackson.Artist#name"))
        return "Artist-Name";
        return super.nameForField(config, field, defaultName);
}

@Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
  if (method.getAnnotated().getDeclaringClass().equals(Album.class) && defaultName.equals("title"))
        return "Album-Title";
        return super.nameForGetterMethod(config, method, defaultName);
  }
});

The json now looks like this

{
  "Album-Title" : "Kind Of Blue",
  "links" : [ "link1", "link2" ],
  "songs" : [ "So What", "Flamenco Sketches", "Freddie Freeloader" ],
  "artist" : {
    "Artist-Name" : "Miles Davis",
    "birthDate" : "26 May 1926"
  },
  "musicians" : {
    "Julian Adderley" : "Alto Saxophone",
    "Miles Davis" : "Trumpet, Band leader",
    "Paul Chambers" : "double bass"
  }
}

Let us now see how Jackson handles null. we add three new properties to the Artist class and do not assign values to them. we add age(int), homeTown(String) and awardsWon (String[])

public int age;
public String homeTown;
public List<String> awardsWon = new ArrayList<String>();

Here’s how they look after converting to json

"age" : 0,
 "homeTown" : null,
 "awardsWon" : [ ]

we use this configuration to ignore properties that are empty

mapper.setSerializationInclusion(Include.NON_EMPTY);

To explicitely ignore a field use filters are described in this tutorial. Here’s the complete example

package com.studytrails.json.jackson;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

public class SerializationExample {

    public static void main(String[] args) throws IOException, ParseException {
        ObjectMapper mapper = new ObjectMapper();
        Album album = new Album("Kind Of Blue");
        album.setLinks(new String[] { "link1", "link2" });
        List<string> songs = new ArrayList<string>();
        songs.add("So What");
        songs.add("Flamenco Sketches");
        songs.add("Freddie Freeloader");
        album.setSongs(songs);
        Artist artist = new Artist();
        artist.name = "Miles Davis";
        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
        artist.birthDate = format.parse("26-05-1926");
        album.setArtist(artist);
        album.addMusician("Miles Davis", "Trumpet, Band leader");
        album.addMusician("Julian Adderley", "Alto Saxophone");
        album.addMusician("Paul Chambers", "double bass");
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        SimpleDateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy");
        mapper.setDateFormat(outputFormat);
        mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
            @Override
            public String nameForField(MapperConfig<!--?--> config, AnnotatedField field, String defaultName) {
                if (field.getFullName().equals("com.studytrails.json.jackson.Artist#name"))
                    return "Artist-Name";
                return super.nameForField(config, field, defaultName);
            }

            @Override
            public String nameForGetterMethod(MapperConfig<!--?--> config, AnnotatedMethod method, String defaultName) {
                if (method.getAnnotated().getDeclaringClass().equals(Album.class) && defaultName.equals("title"))
                    return "Album-Title";
                return super.nameForGetterMethod(config, method, defaultName);
            }
        });
        mapper.setSerializationInclusion(Include.NON_EMPTY);
        mapper.writeValue(System.out, album);
    }
}

class Album {
    private String title;
    private String[] links;
    private List<string> songs = new ArrayList<string>();
    private Artist artist;
    private Map<string ,="" string=""> musicians = new HashMap<string ,="" string="">();

    public Album(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setLinks(String[] links) {
        this.links = links;
    }

    public String[] getLinks() {
        return links;
    }

    public void setSongs(List<string> songs) {
        this.songs = songs;
    }

    public List<string> getSongs() {
        return songs;
    }

    public void setArtist(Artist artist) {
        this.artist = artist;
    }

    public Artist getArtist() {
        return artist;
    }

    public Map<string ,="" string=""> getMusicians() {
        return Collections.unmodifiableMap(musicians);
    }

    public void addMusician(String key, String value) {
        musicians.put(key, value);
    }
}

class Artist {
    public String name;
    public Date birthDate;
    public int age;
    public String homeTown;
    public List<string> awardsWon = new ArrayList<string>();
}

</string></string></string></string></string></string></string></string></string></string></string>

This is the first part of the tutorial where we saw how to convert a java object to json. in the next part we see how to build a JSON using a tree approach.

Creating JSON Using a Tree Model

It is also possible to build a json using a simple tree model. This could be useful if you dont want to write classes for your JSON structure. We will use the same example as above i.e. an album that has an array songs, an artist and an array of musicians. To write a tree you need to first do this setup:

  • Create a JsonNodeFactory to create the nodes
  • Create a JsonGenerator from a JsonFactory and specify the output method. In this method we print to console.
  • Create an ObjectMapper that will use the jsonGenerator and the root node to create the JSON.

After setting it all up we create a single root node for album. Note that by default the object mapper does not name the root node.

package com.studytrails.json.jackson;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;

public class SerializationExampleTreeModel {
    public static void main(String[] args) throws IOException {
        // Create the node factory that gives us nodes.
        JsonNodeFactory factory = new JsonNodeFactory(false);

        // create a json factory to write the treenode as json. for the example
        // we just write to console
        JsonFactory jsonFactory = new JsonFactory();
        JsonGenerator generator = jsonFactory.createGenerator(System.out);
        ObjectMapper mapper = new ObjectMapper();

        // the root node - album
        JsonNode album = factory.objectNode();
        mapper.writeTree(generator, album);

    }

}

This prints

{}

A lot of lines of code to print two brackets! but lets see how it is to build our json now. We first add the first property of the album i.e. ‘Album-Title’.

album.put("Album-Title", "Kind Of Blue");

This is how our JSON looks now

{"Album-Title":"Kind Of Blue"}

We now add the links array

ArrayNode links = factory.arrayNode();
links.add("link1").add("link2");
album.put("links", links);

The JSON

{"Album-Title":"Kind Of Blue","links":["link1","link2"]}

Next we add the artist object. Note that artist by itself is a JsonObject. we add that to the album.

ObjectNode artist = factory.objectNode();
artist.put("Artist-Name", "Miles Davis");
artist.put("birthDate", "26 May 1926");
album.put("artist", artist);

The JSON

{"Album-Title":"Kind Of Blue","links":["link1","link2"],
"artist":{"Artist-Name":"Miles Davis","birthDate":"26 May 1926"}}

We not add the musicians. The musicians are not in an array but there is an object of type musicians. We therefore create an object.

ObjectNode musicians = factory.objectNode();
musicians.put("Julian Adderley", "Alto Saxophone");
musicians.put("Miles Davis", "Trumpet, Band leader");
album.put("musicians", musicians);

The JSON

{"Album-Title":"Kind Of Blue","links":["link1","link2"],
"artist":{"Artist-Name":"Miles Davis","birthDate":"26 May 1926"},
"musicians":{"Julian Adderley":"Alto Saxophone","Miles Davis":"Trumpet, Band leader"}}

You can similarly add other elements. If you have multiple albums then you would probably generate an array in a for loop. It would typically be faster to generate JSON from a Java Object.

Creating JSON Stream

Look at this tutorial to see an example of generating a JSON stream.


(Note: This article’s original links is here )

 Jackson: Introduction Jackson: json and java - Streaming 

Comments