Я только что написал это, что прекрасно, насколько это возможно:
import com.github.salomonbrys.kotson.get import com.github.salomonbrys.kotson.int import com.github.salomonbrys.kotson.jsonObject import com.google.gson.JsonElement import com.google.gson.JsonObject abstract class BatchJobPayload { abstract fun toJson(): JsonObject } class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload() { constructor(payload: JsonElement) : this(payload["bookingId"].int) override fun toJson() = jsonObject( "bookingId" to bookingId ) }
Но я хотел бы настаивать, если это возможно, что все классы, расширяющие BatchJobPayload
реализуют вторичный конструктор с constructor(payload: JsonElement): BatchJobPayload
подписи constructor(payload: JsonElement): BatchJobPayload
, который должен использоваться для десериализации.
BookingConfirmationMessagePayload
имеет такой конструктор, но только потому, что я положил его туда, а не потому, что BatchJobPayload
настаивал на этом …
Я применил следующий вариант:
interface BatchJobPayload { fun toJson(): JsonObject } interface BatchJobPayloadDeserialize { operator fun invoke(payload: JsonElement): BatchJobPayload } class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload { override fun toJson() = jsonObject( "bookingId" to bookingId ) } class BookingConfirmationMessagePayloadDeserialize : BatchJobPayloadDeserialize { override operator fun invoke(payload: JsonElement) = BookingConfirmationMessagePayload(payload["bookingId"].int) }
Теперь вы можете десериализовать объект BookingConfirmationMessagePayload
из JsonElement
следующим образом:
BookingConfirmationMessagePayloadDeserialize()(payload)
(Оператор invoke
– это просто какой-то синтаксический сахар здесь, который может оказаться на тупых …)
На самом деле я по-прежнему предпочитаю оригинальный код, который является менее подробным. Разработчик, нуждающийся в подклассе BatchJobPayload
в будущем, может вначале пренебречь определением конструктора, который принимает JsonElement
но они наверняка осознают свое упущение, если у них есть только строка JSON, которая они должны превратиться в экземпляр своего нового класса …
Вы не можете применять супер-конструктор, но вы можете иметь фабрики с принудительным BatchJobPayload
метода spawn, который возвращает подкласс BatchJobPayload
, который позволяет вам убедиться, что классы будут конструктивными.
Это будет выглядеть примерно так:
class JsonObject // Included to make compiler happy abstract class Factory<T> { abstract fun make(obj: JsonObject): T } abstract class Base { abstract fun toJson(): JsonObject } class A(val data:JsonObject):Base() { override fun toJson(): JsonObject { return JsonObject() } } class AFactory: Factory<A>() { override fun make(obj: JsonObject): A { return A(obj) } } fun main(args: Array<String>) { val dummyJson = JsonObject() var factory = AFactory() var instance = factory.make(dummyJson) println(instance) }