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.
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?
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.