1. Overview
In this tutorial, we’ll discuss the Jackson support for Kotlin.
We’ll explore how to serialize and deserialize both Objects and Collections. We’ll also make use of @JsonProperty and @JsonInclude annotations.
2. Maven Configuration
First, we need to add the jackson-module-kotlin dependency to our pom.xml:
<dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-kotlin</artifactId> <version>2.9.8</version> </dependency>
The latest version of jackson-module-kotlin can be found on Maven Central.
3. Object Serialization
Let’s start with object serialization.
Here we have a simple data Movie class that we’ll use in our examples:
data class Movie( var name: String, var studio: String, var rating: Float? = 1f)
In order to serialize and deserialize objects, we’ll need to have an instance of ObjectMapper for Kotlin.
We can create one using jacksonObjectMapper():
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper val mapper = jacksonObjectMapper()
Or we can create an ObjectMapper and then register KotlinModule:
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule val mapper = ObjectMapper().registerModule(KotlinModule())
Now that we have our mapper, let’s use it to serialize a simple Movie object.
We can serialize an object to a JSON string using the method writeValueAsString():
@Test fun whenSerializeMovie_thenSuccess() { val movie = Movie("Endgame", "Marvel", 9.2f) val serialized = mapper.writeValueAsString(movie) val json = """ { "name":"Endgame", "studio":"Marvel", "rating":9.2 }""" assertEquals(serialized, json) }
4. Object Deserialization
Next, we’ll use our mapper to deserialize a JSON String to a Movie instance.
We’ll use the method readValue():
@Test fun whenDeserializeMovie_thenSuccess() { val json = """{"name":"Endgame","studio":"Marvel","rating":9.2}""" val movie: Movie = mapper.readValue(json) assertEquals(movie.name, "Endgame") assertEquals(movie.studio, "Marvel") assertEquals(movie.rating, 9.2f) }
Note that we don’t need to provide TypeReference to readValue() method; we only need to specify the variable type.
We can also specify the class type in a different way:
val movie = mapper.readValue<Movie>(json)
While deserializing, if a field is missing from JSON String, the mapper will use the default value declared in our class for that field.
Here our JSON String is missing rating field, so the default value 1 was used:
@Test fun whenDeserializeMovieWithMissingValue_thenUseDefaultValue() { val json = """{"name":"Endgame","studio":"Marvel"}""" val movie: Movie = mapper.readValue(json) assertEquals(movie.name, "Endgame") assertEquals(movie.studio, "Marvel") assertEquals(movie.rating, 1f) }
5. Working with Maps
Next, we’ll see how to serialize and deserialize Maps using Jackson.
Here we’ll serialize a simple Map<Int, String>:
@Test fun whenSerializeMap_thenSuccess() { val map = mapOf(1 to "one", 2 to "two") val serialized = mapper.writeValueAsString(map) val json = """ { "1":"one", "2":"two" }""" assertEquals(serialized, json) }
Next, when we deserialize the map, we need to make sure to specify the key and value types:
@Test fun whenDeserializeMap_thenSuccess() { val json = """{"1":"one","2":"two"}""" val aMap: Map<Int,String> = mapper.readValue(json) assertEquals(aMap[1], "one") assertEquals(aMap[2], "two") }
6. Working with Collections
Now, we’ll see how to serialize collections in Kotlin.
Here we have a List of movies that we want to serialize to a JSON String:
@Test fun whenSerializeList_thenSuccess() { val movie1 = Movie("Endgame", "Marvel", 9.2f) val movie2 = Movie("Shazam", "Warner Bros", 7.6f) val movieList = listOf(movie1, movie2) val serialized = mapper.writeValueAsString(movieList) val json = """ [ { "name":"Endgame", "studio":"Marvel", "rating":9.2 }, { "name":"Shazam", "studio":"Warner Bros", "rating":7.6 } ]""" assertEquals(serialized, json) }
Now when we deserialize a List, we need to provide the object type Movie – just like we did with the Map:
@Test fun whenDeserializeList_thenSuccess() { val json = """[{"name":"Endgame","studio":"Marvel","rating":9.2}, {"name":"Shazam","studio":"Warner Bros","rating":7.6}]""" val movieList: List<Movie> = mapper.readValue(json) val movie1 = Movie("Endgame", "Marvel", 9.2f) val movie2 = Movie("Shazam", "Warner Bros", 7.6f) assertTrue(movieList.contains(movie1)) assertTrue(movieList.contains(movie2)) }
7. Changing a Field Name
Next, we can change a field name during serialization and deserialization using @JsonProperty annotation.
In this example, we’ll rename the authorName field to author for a Book data class:
data class Book( var title: String, @JsonProperty("author") var authorName: String)
Now when we serialize a Book object, author is used instead of authorName:
@Test fun whenSerializeBook_thenSuccess() { val book = Book("Oliver Twist", "Charles Dickens") val serialized = mapper.writeValueAsString(book) val json = """ { "title":"Oliver Twist", "author":"Charles Dickens" }""" assertEquals(serialized, json) }
The same goes for deserialization as well:
@Test fun whenDeserializeBook_thenSuccess() { val json = """{"title":"Oliver Twist", "author":"Charles Dickens"}""" val book: Book = mapper.readValue(json) assertEquals(book.title, "Oliver Twist") assertEquals(book.authorName, "Charles Dickens") }
8. Excluding Empty Fields
Finally, we’ll discuss how to exclude empty fields from serialization.
Let’s add a new field called genres to the Book class. This field is initialized as emptyList() by default:
data class Book( var title: String, @JsonProperty("author") var authorName: String) { var genres: List<String>? = emptyList() }
All fields are included by default in serialization – even if they are null or empty:
@Test fun whenSerializeBook_thenSuccess() { val book = Book("Oliver Twist", "Charles Dickens") val serialized = mapper.writeValueAsString(book) val json = """ { "title":"Oliver Twist", "author":"Charles Dickens", "genres":[] }""" assertEquals(serialized, json) }
We can exclude empty fields from JSON using @JsonInclude annotation:
@JsonInclude(JsonInclude.Include.NON_EMPTY) data class Book( var title: String, @JsonProperty("author") var authorName: String) { var genres: List<String>? = emptyList() }
That will exclude fields that are null, an empty Collection, an empty Maps, an array with zero length, and so on:
@Test fun givenJsonInclude_whenSerializeBook_thenEmptyFieldExcluded() { val book = Book("Oliver Twist", "Charles Dickens") val serialized = mapper.writeValueAsString(book) val json = """ { "title":"Oliver Twist", "author":"Charles Dickens" }""" assertEquals(serialized, json) }
9. Conclusion
In this article, we learned how to use Jackson to serialize and deserialize objects in Kotlin.
We also learned how to use @JsonProperty and @JsonInclude annotations.
The full source code can be found on GitHub.