隐式转换旧版本的数据模型



我有一个数据结构,我正在使用Jackson数据绑定将这个数据结构序列化到json文件。随着时间的推移,数据模型发生了变化,但我的应用程序仍然需要能够读取旧版本的JSON。我的意图是,当遇到旧版本的JSON时,它被隐式地转换为内存中数据结构的新版本,当下一次序列化时,它被存储为新格式版本。

对于新添加的属性,这很简单:我只需在Kotlin中指定一个默认值,如果JSON中缺少该属性,Jackson使用该默认值。然而,这种情况更复杂:之前,我有以下数据结构:

data class Options(
var applyClahePerColorChannel: Boolean = false
)

现在,我想使其更通用,并将数据结构更改为以下格式:

data class Options(
var multichannelMode: MultichannelMode = MultichannelMode.ApplyToLuminance
)
enum class MultichannelMode {
ApplyToLuminance, ApplyToAllColorsSeparately
}

现在,当读取旧版本的JSON时,applyClahePerColorChannel == false应该隐式地转换为multichannelMode == ApplyToLuminance,applyClahePerColorChannel == true应该隐式地转换为multichannelMode == ApplyToAllColorsSeparately

我怎样才能在Jackson中用简洁的方式做到这一点?

这是我找到的一个解决方案,但我仍然愿意接受更好的建议。

一个简单的重命名属性可以用@JsonAlias处理,像这样:

如果这个数据模型…

data class Options(
var applyClahePerColorChannel: Boolean = false
)

…改变…

data class Options(
var applyPerColorChannel: Boolean = false
)

…旧名称可以作为别名添加,如下所示:

data class Options(
@get:JsonAlias("applyClahePerColorChannel")
var applyPerColorChannel: Boolean = false
)

Jackson将以相同的方式对待这两个名称,但在序列化后,Jackson将使用新名称。

但是,在我的例子中,我还更改了变量的类型,需要像这样的自定义转换器:

data class Options(
@get:JsonAlias("applyClahePerColorChannel")
@get:JsonDeserialize(converter = BooleanToMultichannelModeConverter::class)
var multichannelMode: MultichannelMode = MultichannelMode.ApplyToLuminance
)
class BooleanToMultichannelModeConverter : Converter<String, MultichannelMode> {
override fun convert(value: String): MultichannelMode {
return when (value) {
in listOf("true", "True", "TRUE") -> ApplyToAllColorsSeparately
in listOf("false", "False", "FALSE") -> ApplyToLuminance
else -> MultichannelMode.valueOf(value)
}
}
@OptIn(ExperimentalStdlibApi::class)
override fun getInputType(typeFactory: TypeFactory): JavaType = typeFactory
.constructType(String::class.starProjectedType.javaType)
@OptIn(ExperimentalStdlibApi::class)
override fun getOutputType(typeFactory: TypeFactory): JavaType = typeFactory
.constructType(MultichannelMode::class.starProjectedType.javaType)
}

转换器基本上告诉Jackson自己不要做任何解析,而是简单地将未解析的字符串交给转换器类,它将首先尝试将字符串解析为布尔值,如果失败则将其解析为enum值。

最新更新