Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Одинаковые имена полей с разным типом в JSON

#java #android #json #rest


К примеру, есть модели:

public class Shipment {
     private int id;
     private Destination destination
     private String status;
}

public class Destination {
     private int id;
     private String company;
     private String nameTo;
}

public class Order {
     private int id;
     private String reference;
     private List shipments;
}


Есть JSON ответ чтобы получить Order:

{
    "id": 78,
    "reference": "FD456",
    "shipments": [
                  {
                    "id": 86160,
                    "destination": 172002,
                    "status": "ready"
                  }
}


Есть JSON ответ чтобы получить Shipment:

{
    "id": 86160,
    "destination": [
                  {
                    "id": 172002,
                    "company": "KLM inc",
                    "name_to": "Alex"
                  }
    "status": "ready"
}


Как видно в первом JSON поле destination хранит просто id, а во втором JSON приходит
уже сам объект Destination. Как я понимаю это сделано в целях оптимизации, но вопрос
состоит в том, как хранить такое различие типов в моделях?
    


Ответы

Ответ 1



Такое получилось из-за БД на стороне API С точки зрения API там два разных типа данных: сама модель и ссылка на модель. В самом общем смысле. "Голый id" это ссылка, по которой API может однозначно найти нужную запись. Скорее всего, это внешний ключ в какой-то SQL-базе. Если у вас, потребителя API, есть своя БД, то в ней это можно представить, как поле, хранящее ..._api_id (где ссылка) и api_id (где значение). Как внешний и первичный ключ (соотв-но), но поскольку в базе "снаружи", соответствующие значения есть не всегда. Если пришла ссылка, то сохранить только в это поле, если значение, то сделать строчку в другой таблице и заполнить это поле. А если базы нет, можно завести singleton-мапы id => объект и... дальше варианты. Если вы уверены, что эти объекты меняются редко, эти мапы можно использовать, как кэш. Например, получили вы id, и оказалось, что в мапе эта запись уже есть (ранее у API спрашивалась), можно её сразу и взять. А если считаете, что они меняются часто, то вам придётся делать ещё один запрос, чтобы точно получить самую свежую версию объекта. Можно совместить два подхода, и обновлять объект только если запрос был достаточно давно. Да-да, пресловутый "cache invalidation". Так или иначе, в объекте у вас будет только число — ключ для мапа. Если в мапе такого значения нет, его надо достать с API и записать в мап. Вам стоит поискать в этом API место, которое вам этот объект выдаст целиком. В приведённых JSON-ответах разработчики, вероятно, решили, что данные смежных объектов нужны часто и решили их вложить по значению, а не по ссылке.

Ответ 2



Так а в чём сложность то? Проверяйте при сериализации/десериализации в json какие данные есть и в зависимости от этого или создавайте/меняйте destination, или просто прогружайте по id. Конфликта то с конечной моделью, в которой идёт ссылка на объёкт, а не его id то нету.

Ответ 3



Не суть важно в чем причина такого ответа JSON от сервера. Я так понимаю ТС не контролирует что ему выдает сервер - иначе он бы изменил JSON ответ :) Теперь к сути вопроса: суть если кратко состоит в том, что объект Destination сериализуется иногда как полномасштабный объект, а иногда только как id - вопрос - как обрабатывать это на этапе десериализации (посколько сериализацию мы не контролируем, то остается только этап десериализации). Ответ: Модель оставляем такой как описано у вас. Далее берем Google GSON и пишем десериализатор, примерно так: public class MyDeSerializer implements JsonDeserializer { @Override public Object deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject object = jsonElement.getAsJsonObject(); if (object.has("destination")) return context.deserialize(jsonElement, Destination.class); else return context.deserialize(jsonElement, typeOfT); } } Такой десериализатор, всегда будет заставлять парсить поле destination как объект Destination Финальный штрих - встраивание десериализатора в парсер: GSon gson = new GsonBuilder() .registerTypeAdapter(Object.class, new MyDeSerializer()) .create(); P.S. Писал на коленках, так что не взыщите. Здесь изложена только идея, остальное уже сами.

Ответ 4



Объекты различные - модели будут разные в соответствии с разной структурой объектов. Не стоит делать общую универсальную модель.

Комментариев нет:

Отправить комментарий