最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Jackson annotations and Kotlin value classes - Stack Overflow

programmeradmin1浏览0评论

When a class includes a property that is an inline value class, Jackson ignores all annotations attached to any field of the enclosing class. Minimum reproducible example:

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

data class MyDataClass(val value: String)

@JvmInline
value class MyInlineClass(val value: String)

data class ClassUsingMyDataClass(
    @JsonProperty("fred")
    val myInlineClassField: MyDataClass,
    @JsonProperty("barney")
    val myStringField: String
)

data class ClassUsingMyInlineClass(
    @JsonProperty("fred")
    val myInlineClassField: MyInlineClass,
    @JsonProperty("barney")
    val myStringField: String
)

fun main() {
    val objectMapper = jacksonObjectMapper()

    // Prints {"fred":{"value":"one"},"barney":"two"} as expected
    println(objectMapper.writeValueAsString(ClassUsingMyDataClass(MyDataClass("one"), "two")))

    // Prints {"myInlineClassField":"one","myStringField":"two"}, why doesn't it use fred and barney?
    println(objectMapper.writeValueAsString(ClassUsingMyInlineClass(MyInlineClass("one"), "two")))
}

Is there a way to make @JsonProperty work again, once you've included a field whose type is an inline value class?

I'm using Jackson 2.18.2 and Kotlin 2.1.10.

When a class includes a property that is an inline value class, Jackson ignores all annotations attached to any field of the enclosing class. Minimum reproducible example:

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper

data class MyDataClass(val value: String)

@JvmInline
value class MyInlineClass(val value: String)

data class ClassUsingMyDataClass(
    @JsonProperty("fred")
    val myInlineClassField: MyDataClass,
    @JsonProperty("barney")
    val myStringField: String
)

data class ClassUsingMyInlineClass(
    @JsonProperty("fred")
    val myInlineClassField: MyInlineClass,
    @JsonProperty("barney")
    val myStringField: String
)

fun main() {
    val objectMapper = jacksonObjectMapper()

    // Prints {"fred":{"value":"one"},"barney":"two"} as expected
    println(objectMapper.writeValueAsString(ClassUsingMyDataClass(MyDataClass("one"), "two")))

    // Prints {"myInlineClassField":"one","myStringField":"two"}, why doesn't it use fred and barney?
    println(objectMapper.writeValueAsString(ClassUsingMyInlineClass(MyInlineClass("one"), "two")))
}

Is there a way to make @JsonProperty work again, once you've included a field whose type is an inline value class?

I'm using Jackson 2.18.2 and Kotlin 2.1.10.

Share asked Mar 4 at 10:45 Klitos KyriacouKlitos Kyriacou 11.7k2 gold badges47 silver badges83 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

The @JsonProperty annotation is being applied to the parameters of the primary constructor, simply because it can be. See the last part of this section of the documentation for the precedence of where to apply an annotation when multiple annotation targets are applicable.

This all works fine with a regular data class - Jackson can detect these annotations on the constructor parameters.

However, once you use an inline class as a constructor parameter, there are two constructors being generated. In Java, they'd look like this:

private ClassUsingMyInlineClass(String x, String, y)

public ClassUsingMyInlineClass(String x, String y, DefaultConstructorMarker z)

The JsonProperty annotations are only added to the second overload. I'm not sure if this behaviour is intentional. This is a related bug report on YouTrack.

Anyway, to get this to work, you should just mark the fields with the annotation.

data class ClassUsingMyInlineClass(
    @field:JsonProperty("fred")
    @get:JsonIgnore
    val myInlineClassField: MyInlineClass,
    @field:JsonProperty("barney")
    val myStringField: String
)

Kotlin will also generate a getter for myInlineClassField which has a mangled name (see why here). This confuses Jackson a bit and causes it to write an extra JSON property for the getter, so you need to JsonIgnore the getter.

发布评论

评论列表(0)

  1. 暂无评论