Jackson @JsonProperty注解在Kotlin数据类中的使用

67

kotlin 1.2.10 jackson-module-kotlin:2.9.0

我在kotlin中有以下数据类:

data class CurrencyInfo(
        @JsonProperty("currency_info") var currencyInfo: CurrencyInfoItem?
)

@JsonInclude(JsonInclude.Include.NON_NULL)
data class CurrencyInfoItem(
        @JsonProperty("iso_4217") var iso4217: String?,
        @JsonProperty("name") var name: String?,
        @JsonProperty("name_major") var nameMajor: String?,
        @JsonProperty("name_minor") var nameMinor: String?,
        @JsonProperty("i_ma_currency") var iMaCurrency: Int?,
        @JsonProperty("i_merchant_account") var iMerchantAccount: Int?,
        @JsonProperty("i_x_rate_source") var iXRateSource: Int?,
        @JsonProperty("base_units") var baseUnits: Double?,
        @JsonProperty("min_allowed_payment") var minAllowedPayment: Int?,
        @JsonProperty("decimal_digits") var decimalDigits: Int?,
        @JsonProperty("is_used") var isUsed: Boolean?
)
当我尝试对此数据类进行反序列化时,我会得到以下结果:
{"currency_info":{"iso_4217":"CAD","name":"Canadian Dollar","imerchantAccount":0,"ixrateSource":2}}

正如您所看到的,最后两个选项被错误地反序列化了。通过直接在getter上添加注释@get:JsonProperty,可以解决此问题。但是,根据jackson文档,@JsonProperty应该分配给getter / setter /字段。

因此,我想问是否有一种可靠的方法在Kotlin中为jackson注释属性以进行正确的序列化/反序列化(而且我的所有数据类都是自动生成的,因此很难分别为getter和setter创建某些两/三行注释)

否则,此问题是否可以通过某些jackson设置解决?

根据下面的答案,以下对我起作用

private val mapper = ObjectMapper().registerKotlinModule()
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)

你只需要使用以下代码:.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY).setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)。问题取决于“is” getter 的特定处理方式。 - Beloo
8个回答

95

您的代码中的@JsonProperty注释都放在数据类中的私有字段上,而默认情况下,Jackson不会扫描私有字段以查找注释。您必须通过放置@JsonAutoDetect注释来指示它执行其他操作:

@JsonProperty注释应用于数据类中的私有字段,而默认情况下Jackson不会扫描私有字段以查找注释。您需要使用@JsonAutoDetect注释告诉Jackson执行其他操作。

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
data class CurrencyInfo(
    @JsonProperty("currency_info") var currencyInfo: CurrencyInfoItem?
)

或者您可以将注释移到访问器方法上:

data class CurrencyInfo(
    @get:JsonProperty("currency_info") var currencyInfo: CurrencyInfoItem?
)

谢谢,我已经全局设置了可见性修饰符。 - Mike
1
我有jackson-annotations-2.9.0,但没有PRIVATE选项。我尝试使用ANY,但该属性仍被忽略。查看源代码 - Mario Trucco
3
如果您正在尝试复制某些内容,而该内容在获取值时不会发生(即在构造时发生的自定义Json反序列化器),那么使用@param:JsonProperty("")下面的答案也是至关重要的。 - Bwvolleyball
这些对我都不起作用。 - Richa Shah
嗨,在Java中,序列化和反序列化时可以有不同的jsonproperty名称。在Kotlin数据类中,是否可以做类似的事情?我看到了 @get:JsonProperty 但没有 @set:Jsonproperty。https://dev59.com/eGoy5IYBdhLWcg3wa9ff - firstpostcommenter
显示剩余2条评论

20

你可以像这样做:

data class CurrencyInfo @JsonCreator constructor (
        @param:JsonProperty("currency_info") 
        @get:JsonProperty("currency_info")
        val currencyInfo: CurrencyInfoItem?
)

上面的代码在Java中翻译为:

public final class CurrencyInfo {
   @Nullable
   private final String currencyInfo;

   @JsonProperty("currency_info")
   @Nullable
   public final String getCurrencyInfo() {
      return this.currencyInfo;
   }

   @JsonCreator
   public CurrencyInfo(@JsonProperty("currency_info") @Nullable String currencyInfo) {
      this.currencyInfo = currencyInfo;
   }
}

被采纳答案的代码如下翻译成Java:

首先(不是完全不可变的):

@JsonAutoDetect(
   fieldVisibility = Visibility.ANY
)
public final class CurrencyInfo {
   @Nullable
   private String currencyInfo;

   @Nullable
   public final String getCurrencyInfo() {
      return this.currencyInfo;
   }

   public final void setCurrencyInfo(@Nullable String var1) {
      this.currencyInfo = var1;
   }

   public CurrencyInfo(@JsonProperty("currency_info") @Nullable String currencyInfo) {
      this.currencyInfo = currencyInfo;
   }
}

第二个(可能在反序列化方面存在问题):

public final class CurrencyInfo {
   @Nullable
   private final String currencyInfo;

   @JsonProperty("currency_info")
   @Nullable
   public final String getCurrencyInfo() {
      return this.currencyInfo;
   }

   public CurrencyInfo(@Nullable String currencyInfo) {
      this.currencyInfo = currencyInfo;
   }
}

17

2
它从一开始就被使用了。你甚至可以在问题帖子中检查初始化。 - Mike
1
@Mike 是的,我错过了那个。但它对我来说完成了工作。 - GameScripting
到目前为止,这是最好的答案:注册此模块不仅可以解决问题,而无需键入@get:或使用其他调整,而且还可以改善Kotlin<>Jackson互操作性。 - madhead
KotlinModule()在最新版本的jackson中不可用,但所有文档都谈到了使用KotlinModule()的方法。不幸的是,没有人说明如何在最新版本中实现它。 - metis
@metis 请查看 https://github.com/FasterXML/jackson-module-kotlin#usage: ObjectMapper().registerKotlinModule() - GameScripting

6

Kotlin不支持@param和@get注解作为一个注解,因此我们必须编写这样的代码:

data class User(
    @param:JsonProperty("id") @get:JsonProperty("id") val id: Int,
    @param:JsonProperty("name") @get:JsonProperty("name") val name: String
)

在这里,您可以告诉JetBrain团队支持此功能并允许:

data class User(
    @JsonProperty("id") val id: Int,
    @JsonProperty("name") val name: String
)

https://youtrack.jetbrains.com/issue/KT-11005


4
您可以通过调用setPropertyNamingStrategy(...)方法来配置jackson库中的ObjectMapper。
使用PropertyNamingStrategy.SNAKE_CASE应该可以解决您的问题。
在此处还可以查看其他可用策略:PropertyNamingStrategy

3
谢谢,这是一个好主意,我已经尝试过了。但是默认的SNAKE_CASE翻译实现较差。许多字段被错误地解析。例如,iso4217->未被正确翻译成iso_4217,iXRateSource->i_x_rate_source等。 - Mike

3
这个问题已经在以下链接中解决: https://github.com/FasterXML/jackson-module-kotlin/issues/237 或者您也可以使用其他方法。
data class SignRequest    
    @param:JsonProperty("estamp_request")
    @get:JsonProperty("estamp_request")
    val eStamp: EstampRequest?
}

data class EstampRequest(
    val tags: Map<String,Int>
)

就我所看,这个问题在我撰写时仍未得到解决,但评论中有一些解决方法。 - Vic

1
今天我遇到了这个问题,我所做的是在我的ObjectMapper()中注册KotlinModule()。下面是一个示例。
@Bean fun objectMapper = ObjectMapper().registreModule(KotlinModule())

上面是一个虚拟的objectMapper,我相信你应该在你的objectMapper中放置其他配置,比如序列化器等等。


0
在我的情况下,只有这个映射器起作用:
    @Bean
    fun objectMapper(): ObjectMapper =
        jacksonObjectMapper()
            .setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

在每个字段上使用@JsonProperty(即使是一个单词命名的字段),并使用默认构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接