Как использовать PolymorphicJsonAdapterFactory с интерфейсом в Moshi?

У меня есть интерфейс с двумя конкретными типами как часть моей модели, которую я хотел бы сериализовать/десериализовать с помощью Moshi. Моя проблема в том, что я не совсем понимаю, действительно ли PolymorphicJsonAdapterFactory предназначен для моего варианта использования. Я просмотрел образцы и несколько сообщений в блогах, и (если я правильно их понимаю) все они, похоже, указывают на тот факт, что ваш интерфейс должен иметь поле в интерфейсе, которое позволяет вам определить тип . Я работаю в существующей кодовой базе, и поэтому я не могу легко добавить поле, которое позволило бы мне выяснить, к какому типу оно относится, по какому-то строковому литералу.

Вот где я нахожусь со своим кодом Moshi, и я ищу подтверждение того, правильно ли я использую PolymorphicJsonAdapterFactory. Примечание. Я использую java для моши-части кода и для своей модели. Мой интерфейс и его конкретные типы в kotlin

String json = ...;

Moshi moshi = new Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(PersonInterface.java, "")
            .withSubtype(BusinessPerson.java, "occupation")
            .withSubtype(PolicePerson.java, "rank")
)
.build();
JsonAdapter<MyModel> jsonAdapter = moshi.adapter(MyModel.class);

MyModel myModel = jsonAdapter.fromJson(json);

Примечание. Я использую java для моши-части кода и для своей модели. Мой интерфейс и его конкретные типы в kotlin

MyModel определяется следующим образом

class MyModel {
    String month;
    PersonInterface person;
}

Мой интерфейс и конкретные классы в kotlin:

Interface PersonInterface {
    val personsName: String?
}

data class BusinessPerson(
        override val personsName: String,
        val occupation: String?
) : PersonInterface

data class PolicePerson(
    override val personsName: String,
    val rank: String?
) : PersonInterface

Цель состоит в том, чтобы Моши мог создать

class MyModel {
    String month;
    BusinessPerson person;
}

or a

class MyModel {
    String month;
    PolicePerson person;
}

в зависимости от того, содержит ли поле человека occupation (что означает, что оно имеет тип BusinessPerson) или содержит ли оно поле rank (что означает, что оно имеет тип PolicePerson).


person coltonidle    schedule 30.12.2019    source источник


Ответы (1)


PolymorphicJsonAdapterFactory.of(PersonInterface.java, "")
    .withSubtype(BusinessPerson.java, "occupation")
    .withSubtype(PolicePerson.java, "rank")

означает, что JSON для каждого человека должен содержать ключ "", а "occupation" или "rank" - это значение для этого ключа, а не само имя ключа, как вы хотите. Так, например. он будет кодировать

BusinessPerson("John", "CEO")

as

{"": "occupation", "personsName": "John", "occupation": "CEO"}

Я думаю, вам придется написать свою собственную фабрику адаптеров для этого варианта использования, если вы хотите избежать поля дискриминатора.

person Alexey Romanov    schedule 30.12.2019
comment
Также обратите внимание, что поле типа находится в модели JSON, а не в типе Kotlin. - person Jesse Wilson; 30.12.2019
comment
@Алексей спасибо за разъяснение. Похоже, я совершенно неправильно понял это. С вашей точки зрения, для моего варианта использования мне пришлось бы написать свою собственную фабрику адаптеров? У тебя случайно нет образца того, как я это напишу? Я действительно думал, что PolymorphicJsonAdapterFactory сможет помочь здесь, но, похоже, это поможет только в том случае, если мой тип прописан в json. - person coltonidle; 30.12.2019
comment
@coltonidle Я думаю, что источник PolymorphicJsonAdapterFactory на самом деле лучшая отправная точка. Он находится по адресу github.com/square/moshi/blob/master/adapters/src/main/java/com/. В частности, посмотрите на методы fromJson и toJson, это то, что вам нужно изменить. - person Alexey Romanov; 30.12.2019