Suporte de Jackson para Kotlin

Suporte de Jackson para Kotlin

1. Visão geral

Neste tutorial, discutiremos o suporteJackson para Kotlin.

Exploraremos como serializar e desserializarObjects eCollections. Também usaremos as anotações@JsonPropertye@JsonInclude.

2. Configuração do Maven

Primeiro, precisamos adicionar a dependênciajackson-module-kotlin ao nossopom.xml:


    com.fasterxml.jackson.module
    jackson-module-kotlin
    2.9.8

A versão mais recente dejackson-module-kotlin pode ser encontrada no Maven Central.

3. Object serialização

Vamos começar com a serialização de objetos.

Aqui temos uma classe de dadosMovie simples que usaremos em nossos exemplos:

data class Movie(
  var name: String,
  var studio: String,
  var rating: Float? = 1f)

Para serializar e desserializar objetos,we’ll need to have an instance of ObjectMapper for Kotlin.

Podemos criar um usandojacksonObjectMapper():

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

val mapper = jacksonObjectMapper()

Ou podemos criar umObjectMappere registrarKotlinModule:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule

val mapper = ObjectMapper().registerModule(KotlinModule())

Agora que temos nosso mapeador, vamos usá-lo para serializar um objetoMovie simples.

Podemos serializar um objeto para uma string JSON usando o métodowriteValueAsString():

@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 desserialização

A seguir, usaremos nosso mapeador para desserializar uma String JSON para uma instânciaMovie.

Usaremos o métodoreadValue():

@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)
}

Observe que não precisamos fornecer o métodoTypeReference parareadValue(); precisamos apenas especificar o tipo de variável.

Também podemos especificar o tipo de classe de uma maneira diferente:

val movie = mapper.readValue(json)

Durante a desserialização, se um campo estiver faltando na StringJSON, o mapeador usará o valor padrão declarado em nossa classe para esse campo.

Aqui, falta o camporating em nossa string JSON, então o valor padrão1 foi usado:

@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. Trabalhando comMaps

A seguir, veremos como serializar e desserializarMaps usando Jackson.

Aqui, serializaremos umMap<Int, String> simples:

@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)
}

A seguir,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 = mapper.readValue(json)

    assertEquals(aMap[1], "one")
    assertEquals(aMap[2], "two")
}

6. Trabalhando comCollections

Agora, veremos como serializar coleções em Kotlin.

Aqui temosList de filmes que queremos serializar em uma string JSON:

@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)
}

Agora, quando desserializamos aList, precisamos fornecer o tipo de objetoMovie - assim como fizemos comMap:

@Test
fun whenDeserializeList_thenSuccess() {
    val json = """[{"name":"Endgame","studio":"Marvel","rating":9.2},
      {"name":"Shazam","studio":"Warner Bros","rating":7.6}]"""
    val movieList: List = 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. Alterando um nome de campo

A seguir,we can change a field name during serialization and deserialization using @JsonProperty annotation.

Neste exemplo, vamos renomear o campoauthorName paraauthor para uma classe de dadosBook:

data class Book(
  var title: String,
  @JsonProperty("author") var authorName: String)

Agora, quando serializamos um objetoBook,author é usado em vez deauthorName:

@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)
}

O mesmo vale para a desserialização também:

@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. Excluindo campos vazios

Finalmente, discutiremos como excluir campos vazios da serialização.

Vamos adicionar um novo campo chamadogenres à classeBook. Este campo é inicializado comoemptyList() por padrão:

data class Book(
  var title: String,
  @JsonProperty("author") var authorName: String) {
    var genres: List? = emptyList()
}

Todos os campos são incluídos por padrão na serialização - mesmo se foremnull ou vazios:

@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)
}

Podemos excluir campos vazios de JSON usando a anotação@JsonInclude:

@JsonInclude(JsonInclude.Include.NON_EMPTY)
data class Book(
  var title: String,
  @JsonProperty("author") var authorName: String) {
    var genres: List? = emptyList()
}

Isso excluirá campos que sãonull, umCollection vazio, umMaps vazio, uma matriz com comprimento zero e assim por diante:

@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. Conclusão

Neste artigo, aprendemos como usar Jackson para serializar e desserializar objetos no Kotlin.

Também aprendemos como usar as anotações@JsonPropertye@JsonInclude.

E, como sempre, o código-fonte completo pode ser encontradoover on GitHub.