Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 3759

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 61k
Author
Asked: November 26, 20242024-11-26T05:41:08+00:00 2024-11-26T05:41:08+00:00

Adding contextual serialization in Ktor

  • 61k

What is Ktor?

Ktor is a Kotlin framework for building web applications and HTTP services.

This blog post will focus on an issue I ran into recently concerning to JSON serialization when using Ktor (adding contextual serialization).

If you're into Kotlin and you haven't tried Ktor yet, I highly suggest you try it out. You can read more about Ktor here.


JSON Serialization in Ktor

The process of turning objects into JSON data is a common task and most of the time it's a non-issue; turning an Int into a JSON number is simple, turning a String into a JSON string is simple and so on. Eventually you will run into a situation where you need to either customize your serialization logic or provide a serialization implementation for a non-primitive value.

The Ktor docs are great as a start and they even show you how to use three built-in converters (Gson, Jackson and kotlinx.serialization). For my project I'm using kotlinx.serialization and the issue at hand will be solved for that converter, but the concept is the same for the others.

A minimal Ktor setup with JSON serialization might look like this:

@Serializable data class Response(private val value: String)  fun main() {     embeddedServer(Netty, port = 8080, host = "127.0.0.1") {         install(ContentNegotiation) {             json()         }         routing {             get("/") {                 call.respond(Response("Hello World!"))             }         }     }.start(wait = true) } 
Enter fullscreen mode Exit fullscreen mode

As expected, visiting http://localhost:8080 returns the following:

{   "value": "Hello World!" } 
Enter fullscreen mode Exit fullscreen mode


The Issue

Let's illustrate a case where you might run into an issue.

In my project, I want failing requests, those that generate server-side exceptions, to translate these exceptions into response objects with the properties errorMessage and statusCode.

One might start by attempting the following:

@Serializable data class DuplicateEntryException(     private val errorMessage: String,      @Contextual // Required, this specifies that this converter is expected to be found during runtime     private val statusCode: HttpStatusCode = HttpStatusCode.Conflict ) : RuntimeException(errorMessage)  fun main() {     embeddedServer(Netty, port = 8080, host = "127.0.0.1") {         install(ContentNegotiation) {             json()         }         routing {             get("/") {                 // Faked error for simplicity's sake                 call.respond(DuplicateEntryException("This entry already exists"))             }         }     }.start(wait = true) } 
Enter fullscreen mode Exit fullscreen mode

Starting the project now and visiting http://localhost:8080 will result in the following exception:

kotlinx.serialization.SerializationException: Serializer for class 'HttpStatusCode' is not found. 
Enter fullscreen mode Exit fullscreen mode


The Solution

As the exception is telling us, we need to register a serializer for the HttpStatusCode type. There are two ways of doing this, depending on your use case. I will illustrate both variants below.

Our first order of business, which will be used in both solutions, is to define the custom serializer:

object HttpStatusCodeSerializer : KSerializer<HttpStatusCode> {      override fun deserialize(decoder: Decoder): HttpStatusCode =         HttpStatusCode.fromValue(decoder.decodeInt())       override fun serialize(encoder: Encoder, value: HttpStatusCode) {         encoder.encodeInt(value.value)     }      override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("HttpStatusCode", PrimitiveKind.INT) } 
Enter fullscreen mode Exit fullscreen mode

Basically, turn the HttpStatusCode object into a primitive type, Int in this case.

Next up we need to use this, the first way is to add it to our json() converter definition, like so:

fun main() {     embeddedServer(Netty, port = 8080, host = "127.0.0.1") {         install(ContentNegotiation) {             json(Json {                 serializersModule = SerializersModule {                     contextual(HttpStatusCode::class) { HttpStatusCodeSerializer}                 }             })         }         routing {             get("/") {                 // Faked error for simplicity's sake                 call.respond(DuplicateEntryException("This entry already exists"))             }         }     }.start(wait = true) } 
Enter fullscreen mode Exit fullscreen mode

I prefer this solution when you want your serialization to be easily reusable, for example DuplicateEntryException is generic enough to be reused across use cases in the project.

If you want to customize serialization in a more localized fashion, something that might only be used for some specific purpose, you can do the following instead:

@Serializable data class DuplicateEntryException(     private val errorMessage: String,      @Contextual     @Serializable(with = HttpStatusCodeSerializer::class) // Inform which Serializer to use for this property     private val statusCode: HttpStatusCode = HttpStatusCode.Conflict ) : RuntimeException(errorMessage) 
Enter fullscreen mode Exit fullscreen mode


Resources

If you want to learn more about Ktor or kotlinx.serialization, you can read more at the following resources:

  • Content negotiation and serialization
  • kotlinx.serialization for Ktor
  • kotlinx.serialization at GitHub

jsonkotlinktorwebdev
  • 0 0 Answers
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 1k
  • Popular
  • Answers
  • Author

    How to ensure that all the routes on my Symfony ...

    • 0 Answers
  • Author

    Insights into Forms in Flask

    • 0 Answers
  • Author

    Kick Start Your Next Project With Holo Theme

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.