#kotlin #jackson
#kotlin #джексон
Вопрос:
У меня есть модель, которую я не контролирую, которая, например, вкладывает подтип в родительский объект:
{
timestamp: 0,
type: {
eventType: "Foo"
majorVersion: 1
minorVersion: 0
},
data: {
foo: "baz"
}
}
Существующий EXTERNAL_PROPERTY
преобразователь типов может обрабатывать только строковое поле, а не объект.
Ответ №1:
Самоответчик, потому что мне было так сложно разобраться. Используйте пользовательский AsPropertyTypeDeserializer
. Kotlin упрощает это, автоматически регистрируя закрытые подтипы классов, не требуя аннотаций, с обработкой неизвестного типа в качестве дополнительного бонуса:
class Event(
override val timestamp: Long,
val type: EventType,
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type",
visible = true
)
@JsonTypeResolver(EventDataTypeResolverBuilder::class)
val data: EventData
)
class EventType(
val majorVersion: Int,
val minorVersion: Int,
val eventType: String
)
sealed class EventData {
data class Foo(
val foo: String
) : EventData()
data class Bar(
val bar: String
) : EventData()
object Unknown: EventData()
}
class EventDataTypeResolverBuilder : StdTypeResolverBuilder() {
override fun buildTypeDeserializer(
config: DeserializationConfig,
baseType: JavaType,
subtypes: MutableCollection<NamedType>,
): TypeDeserializer {
val idRes = idResolver(
config,
baseType,
subTypeValidator(config),
subtypes,
false,
true
)
return EventDataTypeDeserializer(
baseType,
idRes,
_typeProperty,
_typeIdVisible,
null
)
}
}
class EventDataTypeDeserializer : AsPropertyTypeDeserializer {
constructor(
bt: JavaType,
idRes: TypeIdResolver,
typePropertyName: String,
typeIdVisible: Boolean,
defaultImpl: JavaType?,
) : super(bt, idRes, typePropertyName, typeIdVisible, defaultImpl)
constructor(src: EventDataTypeDeserializer, property: BeanProperty) : super(src, property)
override fun forProperty(prop: BeanProperty): TypeDeserializer {
return if (prop === _property) this else EventDataTypeDeserializer(this, prop)
}
@Throws(IOException::class)
override fun deserializeTypedFromObject(p: JsonParser, ctxt: DeserializationContext): Any? {
val type = p.parsingContext.parent.currentValue as EventType
val typeId = "EventData$${type.eventType}"
return _findDeserializer(ctxt, typeId).deserialize(p, ctxt)
}
override fun _handleUnknownTypeId(ctxt: DeserializationContext, typeId: String): JavaType {
return _idResolver.typeFromId(ctxt, "EventData$Unknown")
}
}