1

Serving JSON content in Ktor as described in HTTP API - Quick Start - Ktor, as shown in the examples, works for common collections (lists, maps, etc.) and data classes. However, if I want to serialize a class that is not a data class and has fields that I want to exclude, how do I specify the fields to be serialized and their serialized names? Assume that I am using Gson, can I do it in the same way as serializing a class object using Gson directly?

Shreck Ye
  • 1,591
  • 2
  • 16
  • 32
  • 1
    Use the gson api, as usual. Non data classes should work fine. You could also just try it out. If you need more help, provide a more specific question. – avolkmann Jun 16 '19 at 20:01

1 Answers1

3

Using Gson, you have a couple of options to the best of my knowledge.

1. Using Transient

If you mark a field with @Transient (transient in Java) this will be excluded from serialization:

data class Foo(
    @Transient val a: Int,
    val b: Int)

Here, b will be serialized and a will not.

This comes with a huge downside - almost every framework in java takes @Transient into account and sometimes you don't want it to be serialized by Gson, but you might want to persist it to the database for example (if you'd be using the same class for both). To account for this, there's another option, using @Expose.

2. Using Expose

You need to create the gson instance using the builder:

val gson = GsonBuilder()
    .excludeFieldsWithoutExposeAnnotation()
    .create();

Now, fields without @Expose won't be serialized:

data class Foo(
    val a: Int,
    @Expose val b: Int)

Again, a will not be serialized, but b will.

3. Using exclusion strategies

A more advanced method is the usage of exclusion strategies. This allows for loads of introspections on the fields. From custom annotations to the field name or type.

Again, you need to create a gson with a builder:

val gson = GsonBuilder()
    .addSerializationExclusionStrategy(strategyInstance)
    .create();

And you define a strategy like:

object : ExclusionStrategy() {
  override fun shouldSkipField(field: FieldAttributes): Boolean {
  }

  override fun shouldSkipClass(clazz: Class<*>): Boolean {
  }
}

inside shouldSkipField you return true when you don't want to serialize the field and false when you do. Because it receives a FieldAttributes you can get a lot of properties from the field such as name and annotations. This allows for very fine-grained control.

Lastly, you can set this strategy for deserialization as well and for both - addDeserializationExclusionStrategy and setExclusionStrategies.

Fred
  • 16,367
  • 6
  • 50
  • 65
  • 1
    Worth noting that ktor passes `GsonBuilder` as the receiver in the gson block: ```install(ContentNegotiation) { gson { // Configure GsonBuilder here } } ``` – avolkmann Jun 17 '19 at 15:26
  • So I can also just use `@SerializedName` to specify the JSON serialized name right? – Shreck Ye Jun 18 '19 at 16:33
  • 1
    Yes. In fact in Android apps we always do because the name of the variable usually gets obfuscated and then the serialized json is completely broken. I don't think you do this in a Backend, but it's still handy if you want a different name. – Fred Jun 18 '19 at 20:23