The Kotlinx Serialization is a powerful and efficient library for serializing and deserializing Kotlin objects. In this tutorial, we'll learn how to configure it for use with RestClient.
1. Add dependencies
Check the latest version Kotlinx serialization plugin
plugins {
...
kotlin("plugin.serialization") version "2.1.0"
}
Check the latest version Kotlin serialization library
dependecies {
...
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
}
2. Create a MessageConverter configuration
import kotlinx.serialization.json.Json
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType
import org.springframework.http.converter.KotlinSerializationStringHttpMessageConverter
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter
@Configuration
class KtxConfig {
@Bean
fun ktxMessageConverter() : KotlinSerializationJsonHttpMessageConverter {
// if you want to ignore unknown keys from json string,
// otherwise make sure your data class has all json keys.
val json = Json { ignoreUnknownKeys = true }
return KotlinSerializationJsonHttpMessageConverter(json)
}
@Bean
fun ktxMessageConverterWithMediaType() : KotlinSerializationStringHttpMessageConverter<Json> {
// if you want to ignore unknown keys from json string,
// otherwise make sure your data class has all json keys.
val json = Json { ignoreUnknownKeys = true }
return object : KotlinSerializationStringHttpMessageConverter<Json>(json, MediaType.TEXT_HTML, MediaType("text", "html")){}
}
}
3. Create a serializable Data Class
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ZipCode(
@SerialName("cep")
val zipCode: String,
@SerialName("logradouro")
val street: String,
@SerialName("uf")
val stateAcron: String,
@SerialName("estado")
val state: String,
@SerialName("regiao")
val region: String,
)
In this example I'm using a ZipCode JSON free API ViaCep
4. Setup your RestClient object
import com.ktxserializationrestclientspringboot.beans.KtxConfig
import com.ktxserializationrestclientspringboot.json.ZipCode
import org.springframework.stereotype.Component
import org.springframework.web.client.RestClient
@Component
class ViaCepGateway(
private val ktxConfig: KtxConfig
) : ZipCodeGateway {
private val restClient: RestClient = RestClient.builder()
.messageConverters {
it.add(0, ktxConfig.ktxMessageConverter())
it.add(1, ktxConfig.ktxMessageConverterWithMediaType())
}
.baseUrl("https://viacep.com.br/ws/")
.build()
override fun getInfoCep(cep: String): ZipCode? {
return restClient.get()
.uri("/{cep}/json", cep)
.retrieve()
.onStatus({ it.is4xxClientError || it.is5xxServerError }, {_, response ->
throw RuntimeException("Fail to find $cep informations. status code: ${response.statusCode}")
})
.body(ZipCode::class.java)
}
}
In this step make sure you have added the proper MessageConverter
.messageConverters {
it.add(0, ktxConfig.ktxMessageConverter())
//it.add(1, ktxConfig.ktxMessageConverterWithMediaType()) only one is needed
}
5. Call your ZipCodeGateway
@Component
class MainCommandLineRunner(
private val getCep: GetZipCode
): CommandLineRunner {
private companion object {
val logger: Logger = LoggerFactory.getLogger(MainCommandLineRunner::class.java)
}
override fun run(vararg args: String?) {
val zipCodeInfo = getCep.execute("01001000")
logger.info(zipCodeInfo.toString())
}
}
Output should be like
ZipCode(zipCode=01001-000, street=Praça da Sé, stateAcron=SP, state=São Paulo, region=Sudeste)
Bonus
If you need to convert the RestClient's response to a list of entities, you'll need to use the ParameterizedTypeReference interface like this:
return restClient.get()
...
.body(object : ParameterizedTypeReference<List<YOUR_CLASS>>() {})
The complete implementation is available here. Feel free to explore and try it out!
Top comments (0)