Search code examples
kotlinserializationdata-class

Kotlin dataclass function is getting called during serialization


I have a couple of data classes in a kotlin project:

data class Animation(
    val title: String,
    val userId: Int,
    val height: Int,
    val width: Int,
    val speed: Int,
    val frames: List<Frame>,
    val id: Int? = null
) {
    fun toJson(): String {
        return ObjectMapper().writeValueAsString(this)
    }

    fun getMeta(): AnimationMeta {
        return AnimationMeta(this.id, this.title)
    }
}

data class AnimationMeta(val id: Int? = null, val title: String)

And I have an API endpoint for getting a particular animation by id:

@GetMapping("/{id}")
fun getAnimation(@PathVariable("id") id: Int): Animation {
    return animationService.getAnimation(id) ?: throw ResponseStatusException(NOT_FOUND)
}

The business logic behind getAnimation just queries the database, maps the row to the Animation data class, and returns it as is. Nothing special in between.

When I actually call this endpoint, my serialized response includes the call to the getMeta method for some reason:

GET http://localhost:8080/rest/animations/35

{
  "title": "Test",
  "userId": 0,
  "height": 0,
  "width": 0,
  "speed": 0,
  "frames": [],
  "id": 35,
  "meta": {
    "id": 35,
    "title": "Test"
  }
}

How is the function getting called? I'm sure this is some detail that I'm not seeing in the kotlin docs, but I can't quite figure it out.

Update

After digging a bit I found that I can use the @JsonIgnore annotation to suppress the function call during serilaization:

    @JsonIgnore
    fun getMeta(): AnimationMeta {
        return AnimationMeta(this.id, this.title)
    }

But I'm leaving the question up because I don't know why I need to use this. I'm used to using it for ignoring properties, but I still don't get why the function call is happening in the first place. It's not like the toJson function is getting called, so why is getMeta getting called?


Solution

  • I don't know how the internal serialization of retrofit work but I think because you use the prefix get retrofit treat it as a backing field for a property named meta. So when retrofit tries to create the Animation class, it create the meta property using the backing field that you provided (the getMeta method).

    So, using the @JsonIgnore annotation will prevent the deserializer to use the backing field.