Как десериализовать объект с GSON, где данные не имеют имени члена / параметра? - PullRequest
0 голосов
/ 13 мая 2018

API

@GET("api/v1/depth")
Call<OrderBook> getOrderBook(@Query("symbol") String paramString, @Query("limit") int limit);

дает такой ответ:

{
    "lastUpdateId": 1027024,
    "bids": [
        [
            "4.00000000",
            "431.00000000", []
        ]
    ],
    "asks": [
        [
            "4.00000200",
            "12.00000000", []
        ]
    ]
}

для десериализации ответа, jsonschema2pojo.org создал класс OrderBook следующим образом:

public class OrderBook {

@SerializedName("lastUpdateId")
public Long lastUpdateId;

@SerializedName("bids")
public List<List<String>> bids = null;

@SerializedName("asks")
public List<List<String>> asks = null;

}

Однако вы можете видеть, что List<List<String>> не является правильным.

Это должно быть что-то похожее на List<List<String, String, List<Void>>>

Однако, без имен членов, это не 'кажется возможным.Было бы замечательно, если бы GSON имел аннотацию, которая идентифицировала бы положение вместо имени.https://google.github.io/gson/apidocs/com/google/gson/annotations/package-summary.html но такой аннотации не существует.

Как правильно получить POJO из такого минималистского ответа?

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

Хорошо, было бы лучше, если бы вы включили исходный источник данной полезной нагрузки. Это дало бы, по крайней мере, несколько подсказок о том, что закодировано в полезной нагрузке:

{
  "lastUpdateId": 1027024,
  "bids": [
    [
      "4.00000000",     // PRICE
      "431.00000000",   // QTY
      []                // Ignore.
    ]
  ],
  "asks": [
    [
      "4.00000200",
      "12.00000000",
      []
    ]
  ]
}

Затем jsonschema2pojo генерирует слишком наивные отображения и не может создать адаптеры типов, которые обычно являются единственным инструментом, который может работать с такими полезными нагрузками. Например:

Следующее отображение может быть легко десериализовано с помощью Java Reflection, и, поскольку вы, вероятно, не собираетесь изменять его состояние, вы можете сделать все его поля final.

final class Order {

    final long lastUpdateId = Long.valueOf(0); // if `0`, then javac inlines 0 everywhere
                                               // so we're kind of cheating
    final List<PriceAndQuantity> bids = null;
    final List<PriceAndQuantity> asks = null;

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("lastUpdateId", lastUpdateId)
                .add("bids", bids)
                .add("asks", asks)
                .toString();
    }

}

Для следующего объекта требуется немного другой способ создания десериализованного значения. В может отсутствовать конструктор, как и в предыдущем отображении (требуется преобразование потока в JSON-дерево специальной структуры, а затем преобразование с помощью Java Reflection), но проще создать его экземпляр вручную.

final class PriceAndQuantity {

    final double price;
    final double quantity;

    private PriceAndQuantity(final double price, final double quantity) {
        this.price = price;
        this.quantity = quantity;
    }

    static PriceAndQuantity of(final double price, final double quantity) {
        return new PriceAndQuantity(price, quantity);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("price", price)
                .add("quantity", quantity)
                .toString();
    }

}

Теперь вот как вы можете сказать Gson, что приведенный выше экземпляр класса может быть десериализован из такого потока JSON.

final class PriceAndQuantityTypeAdapter
        extends TypeAdapter<PriceAndQuantity> {

    private static final TypeAdapter<PriceAndQuantity> instance = new PriceAndQuantityTypeAdapter()
            .nullSafe();

    private PriceAndQuantityTypeAdapter() {
    }

    static TypeAdapter<PriceAndQuantity> get() {
        return instance;
    }

    @Override
    public void write(final JsonWriter out, final PriceAndQuantity value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public PriceAndQuantity read(final JsonReader in)
            throws IOException {
        in.beginArray();
        final double price = in.nextDouble(); // Indicated as PRICE in the documentation
        final double quantity = in.nextDouble(); // Indicated as QTY in the documentation
        // BEGIN alternative to in.skipValue()
        // JsonReader.skipValue consumes any JSON literal,
        // but here we assert a sequence of [ and ] explicitly
        in.beginArray();
        in.endArray();
        // END alternative to in.skipValue()
        in.endArray();
        return PriceAndQuantity.of(price, quantity);
    }

}
private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(PriceAndQuantity.class, PriceAndQuantityTypeAdapter.get())
        .create();

public static void main(final String... args)
        throws IOException {
    // It just readers the JSON you've put in the question from a resource package
    try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50317182.class, "response.json") ) {
        final Order order = gson.fromJson(jsonReader, Order.class);
        System.out.println(order);
    }
}

Вот пример вывода:

Order {lastUpdateId = 1027024, ставки = [PriceAndQuantity {цена = 4.0, количество = 431.0}], запрашивает = [PriceAndQuantity {цена = 4.000002, количество = 12.0}]}

0 голосов
/ 13 мая 2018

Вы не можете использовать List<List<String>> в качестве третьего индекса внутреннего списка - это массив / список , а не String,

Итак, в вашем случае вы должны использовать List<List<Object>>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...