Как сделать класс для работы с JSON, который может содержать в себе объекты разных типов?

От API сервера приходит JSON вида

{  
    'field1':'<string>',
    'field2':'string','
     list':[{
               'id':'123',
               'uid':'123',
               'date':'<datetime dd.mm.yyyy hh:mi:ss>',
               'msg':{<message в json формате>}},...
             ], ...}


Форматы аттрибута msg:
Сообщение 1: {'txt':''}
Сообщение 2: {'txt':'','btns':[{'cap':'','val':''},...]}
Сообщение 3: {'clst':[{'cap':'','val':''},...]}"

Как видно из JSON, проблема в том, что я не знаю какого типа придут ко мне данные. И как вообще в такой ситуации взаимодействовать с сервером?
Как должен выглядеть класс для получения ответа с сервера?
Пример, как я получаю класс для более простого JSON: www.jsonschema2pojo.org

p.s. Использую для связи с сервером библиотеку retrofit2. Простите за кривое форматирование JSON.
  • Вопрос задан
  • 735 просмотров
Решения вопроса 1
zagayevskiy
@zagayevskiy Куратор тега Java
Android developer at Yandex
С ретрофитом вы наверняка используете какую-нибудь ConverterFactory для преобразования ответа в объект. Например, GsonConverterFactory (GSON). Рассмотрим ситуацию на его примере:
Все объекты описываете как обычно, кроме msg. Его описываете как интерфейс Message. Регистрируете:
class MessageDeserializer implements JsonDeserializer<Message>{ ... }
...
Gson gson = new GsonBuilder()
                .registerTypeAdapter(Message.class, new MessageDeserializer())
                .create();
GsonConverterFactory.create(gson);

В методе
public Message deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ... }

Десериализуете msg на основе тех данных, которые есть (надо научиться различать разные типы msg). Кладёте данные в разные реализации Message, например для {'txt':''} делаете такую реализацию:
class MessageTxt implements Message {
    private final String txt;
    public MessageTxt(String txt){
        this.txt = txt;
    }
    String getTxt() { return txt; }
}

Сам интерфейс Message может вообще не содержать методов (маркерный интерфейс) или содержать общие для всех типов msg методы, или дополнительно содержать метод для возвращения типа. Как-то так я бы поступил, видимо. Разные реализации Message потом можно просто проверять instaceof и кастовать.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@j7sx
А разве весь ответ в json формате не просто строка?
Ну и в зависимости от того как обрабатываете извлекаете уже данные нужного формата.
Не знаю, как в java, но в python это выглядит так:

import sys
import json

response = json.loads(sys.stdin.read())
field1 = response['field1'] #'строка'
lst = response['list']['id'] # '123' - по сути это тоже строка, ибо числа в python без кавычек
если нужно получить число, то можно явно преобразовать в число 
lst = int(lst)
или так, если не знаешь число или не число:
try:
    lst = int(lst)
except ValueError:
    print "преобразовать не получилось"


Надо сказать, что строки, если они имеют вид чисел, скажем 123 или 1.23 преобразуются без проблем.

А если json имеет встроенный json то можно дважды загрузить. сначала загружаешь и получаешь указатель на второй json, потом этот указатель загружаешь (loads) еще раз и получаешь и уже работаешь с ним также, как и раньше.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы