我们使用很多具有单个值的值对象。对于(反)序列化,我们将Jackson与kotlin模块一起使用。
Kotlin中的示例值对象:
data class MyValueObject(val value: String)
或作为Java
class MyValueObject {
private String value;
public MyValueObject(String value) { this.value = value; }
public String getValue() { return value; }
}
这些值对象必须进行序列化和反序列化,并且应序列化为“仅值”,例如。 "theValue"
而不是"{"value":"theValue"}"
。
我想避免为数十个值对象编写自定义序列化器/反序列化器。
我知道对于序列化@JsonValue
可以用来实现上述目的。
data class MyValueObject(@JsonValue val value: String)
但是JSON“” theValue“”(以上序列化的String-Literal)不能反序列化为MyValueObject
。它导致以下异常:
com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot construct instance of `[...].MyValueObject` (although at least one Creator exists):
no String-argument constructor/factory method to deserialize from String value ('test')
at [Source: (String)""test""; line: 1, column: 1]
这是我使用的单元测试:
@Test
fun testSerialize() {
val objectMapper = ObjectMapper()
.registerModule(Jdk8Module())
.registerModule(KotlinModule())
val test = MyValueObject("test")
val json = objectMapper.writeValueAsString(test)
println(json)
objectMapper.readValue<MyValueObject>(json)
}
是否有一种简单/通用的方法来反序列化诸如@JsonValue
进行序列化?
P.S .:一种可行的解决方案(由于@LppEdd)是:
data class MyValueObject (@JsonValue val value: String) {
companion object {
@JvmStatic
@JsonCreator
fun create(value: String) = MyValueObject(value)
}
}
但这很冗长。在构造函数上注释的@JsonCreator对我不起作用(请参阅我对@LppEdd答案的评论)
答案 0 :(得分:3)
当然,这很简单。
只需将@JsonCreator
添加到构造函数即可。
class MyValueObject {
private String value;
@JsonCreator
public MyValueObject(String value) { this.value = value; }
@JsonValue
public String getValue() { return value; }
}
或者我想让Kotlin拥有
data class MyValueObject @JsonCreator constructor(@JsonValue val value: String)
在使用@JsonCreator
时不给构造函数参数加上前缀
@JsonProperty("fieldName")
您告诉Jackson传递整个JSON字符串,在您的情况下,这只是一个“原始”值。
显然Kotlin不喜欢自动生成的getter / setter对。
例如,这有效
class MyValueObject @JsonCreator constructor(private val value: String) {
@JsonValue
fun getValue() = value
}
另外,经过一些调试,我发现问题出在这里
@Override
public Boolean hasAsValue(Annotated a) {
JsonValue ann = _findAnnotation(a, JsonValue.class);
if (ann == null) {
return null;
}
return ann.value();
}
在JacksonAnnotationIntrospector
。
我不知道为什么,但杰克逊仍然在 public 字段或 public 吸气剂上寻找@JsonValue
注释。 Kotlin将注释放在私有字段上,因此Jackson找不到它。
解决方案是
data class MyValueObject @JsonCreator constructor(@JvmField @JsonValue val value: String)
甚至更好
data class MyValueObject @JsonCreator constructor(@get:JsonValue val value: String)
正如马克·冯·伦特恩(Marc von Renteln)在评论中所写,您也可以省略@JsonCreator
data class MyValueObject(@get:JsonValue val value: String)
但是,这似乎没有记录。如果有人可以指出这种行为的描述位置,那就太棒了!