https://kotlinlang.org logo
Title
l

lewik

12/12/2017, 6:54 AM
kotlin.serialization Я ведь правильно понимаю, что ни один из поддерживаемых протоколов не сможет "угадать" в какой именно класс надо десериализовывать объект если в классе указан только интерфейс?
data class Test(
val test: SomeInterface
)
e

elizarov

12/12/2017, 7:03 AM
Cможет, если все фактические экземпляры сераилизуемы. Там всюду поддерживается “полиморфная” сериализация похожая на то, как это сделано в Jackson. Т.е. есть будет записан массив, где первый элемент это строчка — имя класса, а второй элемент это собственно объект.
👍 2
@sandwwraith Может рассказать больше. Планируется в будущем сделать для таких полей специальную аннотацию чтобы полиморфизм не включался по умолчанию (из соображений безопасности), а был исключительно opt-in
l

lewik

12/12/2017, 7:05 AM
Да, он просто еще не онлайн, поэтому я тут спрашиваю. Это конечно круто, я не предполагал такого.
@elizarov А с CBOR/protobuf?
e

elizarov

12/12/2017, 8:32 AM
У CBOR такая же модель. Можно так же делать. В protobuf большого смысла нет, ибо без схемы его нормально не прочитать (там же только id лежать в пакете, нету имен полей)
l

lewik

12/12/2017, 8:33 AM
Не получилось у меня с CBOR угадать в какой класс десериализовывать
interface Test

@Serializable
data class A(var aa: String) : Test

@Serializable
data class B(var bb: String) : Test

@Serializable
data class container(
        val test: Test
)

val container = container(
                A("a") //Ошибка - пишет что нет сериализатора
        )

val dd = dump(container)
Вероятно я что то не так понял
e

elizarov

12/12/2017, 8:48 AM
С интерфейсами может и не работает пока. Если Test это абстрактный класс помеченный @Serializable, то должно работать.
l

lewik

12/12/2017, 8:49 AM
И на js тоже?
e

elizarov

12/12/2017, 8:49 AM
Вроде да. @sandwwraith сможет точней сказать.
s

sandwwraith

12/12/2017, 11:19 AM
На JS не работает, потому что пока что нет “честного” способа по прочитанному класснейму сделать его инстанс на js рантайме
Так что к сожалению, полиморфизм работает пока что только на JVM
l

lewik

12/12/2017, 11:20 AM
Ок, насоздаю полей под каждый тип
s

snrostov

12/12/2017, 11:36 AM
Т.е. есть будет записан массив, где первый элемент это строчка — имя класса, а второй элемент это собственно объект.
Почему именно массив а не просто поле
@type
или
@class
внутри json-объекта?
s

sandwwraith

12/12/2017, 11:39 AM
Парсер в целях перфоманса написан однопроходный, поэтому ему нужно знать тип до того, как он начал читать объект
s

snrostov

12/12/2017, 11:41 AM
Ну, мы тоже написали такой парсер. И он тоже однопроходный, и чатет поле
@type
. Просто реализация метода чтения внутренностей объекта вынесена а отдельный метод. Т.е. идет проверка, если первое поле
@type
, то читаем тип, а далее вызываем метод
readObjectRestContents
единственно условие - поле
@type
должно быть первым
CxJsonElementType.BEGIN_OBJECT -> readObject {
      val nextKey = readNextKey(false)

      when {
      // string keyed map with first key escaped from keyword
        nextKey.startsWith("$") -> stringKeyedMap(readDynamicStringKeyedMapContents(nextKey.substring(1), linker))
      // reference, for example `{ "#class:field": "key value" }`
        nextKey.startsWith("#") -> entityReference(readDynamicReference(nextKey, linker))
      // keyword
        nextKey.startsWith("@") -> {
          val keyword = nextKey.substring(1)
          when (keyword) {
            "structure" -> {
              val valueType = readType(linker)
              structure(readJsonStructureContents(valueType as CxStructure<Any>, linker).instance)
            }
            "map" -> complexKeyedMap(readDynamicComplexKeyedMap(linker))
            "class" -> inlineEntity(readInlineEntityTypeAndContents<Any>(linker).instance)
            else -> error("unknown json @keyword: $nextKey, input: $this")
          }
        }
      // string keyed map
        else -> stringKeyedMap(readDynamicStringKeyedMapContents(nextKey, linker))
      }
    }
Планировали перейти на kotlinx.serialization когда он будет готов, но если типы будут записываться в виде массива, это будет не очень. Можно создать issue по этому поводу чтобы отслеживать?