在我的项目中,我曾经有一个类似于这样的data class
:
data class SampleClassThatContainsALength(val length: Double)
字符串
使用jackson-databind
,SampleClassThatContainsALength(0.025)
将序列化为{"length":0.025}
。
在整个项目中,长度被隐含地假设为米,但为了减少歧义,我实现了一个Length
类,它负责单位:
data class Length(val m: Double) : Comparable<Length> {
@get:JsonIgnore
val km: Double get() = m / 1e3
@get:JsonIgnore
val cm: Double get() = m / 1e-2
@get:JsonIgnore
val mm: Double get() = m / 1e-3
// More conversions to other units...
operator fun plus(other: Length) = (this.m + other.m).m
operator fun minus(other: Length) = (this.m - other.m).m
operator fun unaryMinus() = (-this.m).m
// More operator implementations...
}
val Number.km get() = Length(this.toDouble() * 1e3)
val Number.m get() = Length(this.toDouble())
val Number.cm get() = Length(this.toDouble() * 1e-2)
val Number.mm get() = Length(this.toDouble() * 1e-3)
// More extension functions for other units...
型
因此,数据类现在看起来像这样:
data class SampleClassThatContainsALength(val length: Length)
型
示例对象SampleClassThatContainsALength(0.025.m)
序列化为{"length":{"m":0.025}}
。
我现在有一个问题,我想使用新的序列化,因为它清楚地说明了单元,但我仍然有一些旧的JSON文档(类似于开始时的序列化JSON),我想隐式地转换为新的实现。
所以,总的来说,我希望{"length":0.025}
和{"length":{"m":0.025}}
都能被转换为SampleClassThatContainsALength(0.025.m)
。
现在,{"length":{"m":0.025}}
的虚拟化按照预期工作,但是{"length":0.025}
的虚拟化失败,
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `de.uni_freiburg.inatech.streem.image_converter.common.math.units.Length` (although at least one Creator exists): no double/Double-argument constructor/factory method to deserialize from Number value (0.025)
at [Source: (String)"{"length":0.025}"; line: 1, column: 11] (through reference chain: de.uni_freiburg.inatech.streem.image_converter.data.json.SampleClassThatContainsALength["length"])
型
以下是我到目前为止所做的尝试:
1.我在Length
类中创建了一个companion object
,并添加了以下工厂方法:
companion object {
@JsonCreator
@JvmStatic
fun createFromNumber(number: Number): Length = Length(number.toDouble())
}
型
这会导致{"length":0.025}
的格式化工作,但现在新格式的格式化不再工作:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.Number` from Object value (token `JsonToken.FIELD_NAME`)
at [Source: (byte[])[19 bytes]; byte offset: #7]
型
1.除了伴随对象中的工厂方法,我还尝试用@JsonCreator
标记Length
的主构造函数,如下所示:
data class Length @JsonCreator constructor(val m: Double) : Comparable<Length> {
型
但结果与尝试1完全相同。
1.代替工厂方法,我添加了一个接受Number
(而不是Double
)的二级构造函数:
data class Length(val m: Double) : Comparable<Length> {
constructor(m: Number) : this(m.toDouble())
型
虽然新的格式现在正在工作,但旧的格式仍然被打破。
1条答案
按热度按时间5anewei61#
哇,这比我想象的要快,我有点惭愧,我在发布之前没有找到这个。然而,这里有解决方案,任何人都有同样的问题:
1.保持构造函数不变:
字符串
1.为这两种情况创建两个工厂方法:
型
请注意,
createFromNumber
现在接受String
,而不是Number
或Double
,这似乎很重要。以下是我的灵感来源:
https://github.com/FasterXML/jackson-databind/issues/2353