【问题标题】:Decode generic type with Jackson使用 Jackson 解码泛型类型
【发布时间】:2021-10-22 16:50:30
【问题描述】:

Jackson 不会尝试解码类的通用元素。

如何在不创建特定版本的类的情况下传入类型信息?

数据类型有:

@JsonIgnoreProperties(ignoreUnknown = true)
data class HasuraTriggerPayload<T>(
    val event: HasuraEvent<T>,
    @JsonProperty("created_at")
    val createdAt: Instant,
    val trigger: Trigger
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class HasuraEvent<T>(
    val op: String,
    val data: HasuraData<T>
)

data class HasuraData<T>(
    val old: T,
    val new: T
)

data class Trigger(
    val name: String
)

data class Price(
    val id: UUID,
    val price: BigDecimal?,
)

我的路线是这样的:

post("/price") {
    val payload = call.receive<HasuraTriggerPayload<Price>>()
    // etc
}

这会产生这个错误,因为它不知道如何解码新/旧:

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.scraptickets.rest.models.Price (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.scraptickets.rest.models.Price is in unnamed module of loader 'app')

trigger.name 给出类型。在这种情况下,它是“价格触发”

对此有两种可能的解决方案。

我们知道 T 是我们特定呼叫站点的价格,因此我们可以通过某种方式传递该信息,但是如何传递?

我们可以从trigger.name 中确定oldnew 的类型,但是我们怎么写呢?唯一明显的方法是读取我们试图确定类的对象的字段,而不是从外部读取。

【问题讨论】:

  • 泛型只存在于您的源代码中。当您运行应用程序时,所有泛型都将被删除。你需要告诉 Jackson 你的泛型类型以及如何识别它们。
  • 很公平。我该怎么做?
  • 我已更新数据定义以包含触发器名称。看起来@JsonTypeInfo 可能是可用的,但是当它在数据中的单独层次结构中描述一个类型时,如何使用它并不明显。

标签: java kotlin jackson ktor


【解决方案1】:

经过一番搜索,我找到了解决方案。

您需要创建一个TypeReference

对于我的使用,解决方案是:

post("/price") {
    val typeRef = object : TypeReference<HasuraTriggerPayload<Price>>() { }
    val objectMapper = jacksonObjectMapper() // Not quite this, I'm leaving out the part to handle timestamps
    val jsonStr = call.receiveText()
    val payload = objectMapper.readValue(jsonStr, typeRef)
    // etc
}

【讨论】:

    猜你喜欢
    • 2016-05-27
    • 1970-01-01
    • 2015-09-12
    • 2012-10-18
    • 2011-10-14
    • 2012-07-24
    相关资源
    最近更新 更多