Возник вопрос насчет разбора JSON. Пока что я получаю данные в виде строки. Я бы хотел распарсить в класс через Gson. Дело в том что название заголовка 179746 меняется. Оно может принимать другое имя, все остальное не меняется. Использую для генерации класса jsonschema2pojo , ну если у нас название заголовка становится 10000, то класс сразу становится не используемым
{
"status": "ok",
"meta": {
"count": 1
},
"data": {
"179746": {
"leader_id": 3239400
}
}
}
Может можно как-то убрать тут 179746, и подставить общий параметр, я не знаю как делать.
public class Data {
@SerializedName("179746")
@Expose
private com.example._179746 _179746;
public com.example._179746 get179746() {
return _179746;
}
public void set179746(com.example._179746 _179746) {
this._179746 = _179746;
}
Пока что я делаю так
jsonObject = new JSONObject(getResponse);
JSONObject jsonObject1 = jsonObject.getJSONObject("data");
JSONObject json = jsonObject1.getJSONObject("179746");
Если бы jsonschema2pojo не использовали, количество вопросов связанных с Gson на SO резко бы сократилось вдвое. На это есть следующие причины:
List, Map и т.д.;Кроме того, в Gson не существует JSON*** -- типов с заглавными "JSON" в имени. Это из org.json, в то время как в Gson всегда -- Json***. Дальше, если вы уж и собрались использовать маппинги, их можно использовать почти во всех случаях, и не смешивать их с сущностями, которые представляют JSON-объекты в памяти в виде древовидных структур (т.е., всё семейство JsonElement). Ещё: для объектов с динамическими именами в Gson существует родная поддержка Map<K,V> (впрочем, это справедливо и для Java, поскольку количество имён не известно заранее на этапе компиляции).
Резюмируя вышесказанное, в этом случае нужно просто написать правильные маппинги.
final class Response<T> {
final String status = null;
final Meta meta = null;
final T data = null;
}
final class Meta {
final int count = Integer.valueOf(0);
}
final class Leader {
@SerializedName("leader_id")
final int leaderId = Integer.valueOf(0);
}
Чем это отличается от того, что генерирует тот сервис:
Response<T>);@SerializedName и нет @Expose -- с одной стороны это спорно и противоречит "явному, которое лучше неявного"; с другой -- меньше шума;set***/get***) -- объекты, предназначенные исключительно для переноса данных между компонентами системы (DTO) и которые должны использоваться исключительно сопутствующими компонентами могут опускать это требование хорошего тона, поскольку здесь и инкапсулировать-то нечего;final -- изменяться же не должно (Gson отлично справляется с классами без конструкторов и умеет изменять final-поля во время исполнения; исключение из такого "паттерна": примитивным типам как int не могут присваиватся значения по-умолчанию типа = 0, потому что компилятор просто заинлайнит это значения, и у Gson не будет возможности изменить поле (точнее, места, в которые эта константа заинлайнена) -- поэтому Integer.valueOf(0) является своего рода хаком, чтобы ослепить компилятор).Пример использования:
private static final Gson gson = new Gson();
private static final Type leaderMapResponseType = new TypeToken<Response<Map<Integer, Leader>>>() {
}.getType();
public static void main(final String... args)
throws IOException {
try ( final Reader reader = getPackageResourceReader(Q660527.class, "response.json") ) {
final Response<Map<Integer, Leader>> response = gson.fromJson(reader, leaderMapResponseType);
System.out.println(response.status);
System.out.println(response.meta.count);
for ( final Entry<Integer, Leader> e : response.data.entrySet() ) {
System.out.println(e.getKey() + " => " + e.getValue().leaderId);
}
}
}
Инстансы Gson и Type (по крайней мере те, что порождены с использованием TypeToken<T>) могут считаться иммутабельными и потокобезопасными, поэтому их можно закешировать, не прибегая к повторному созданию экземпляров с теми же характеристиками. Пару слов о том, что такое "type token"-ы. В Java из-за специфики реализации дженериков не существует возможности написать Response<Map<String,Leader>>.class, потому что Class<T> не содержат информации об актуальной параметризации за исключением параметризации родительского класса при наследовании. Возможно, было б очень круто, если бы в Java можно было создавать ad-hoc реализации Type/ParameterizedType примерно как Response<Map<String,Leader>>.type, но увы. Как Gson решает эту проблему? Как я сказал выше, параметризация сохраняется при наследовании, поэтому Gson требует хотя бы анонимной реализации класса TypeToken<T>. При создании экземпляра TypeToken<T> Gson имеет достаточно информации о том, как параметризирован Response<T>, и его вызов getType() возвращает уже проанализированную информацию о параметризированном типе, а не просто о классе. Это эквивалентно ручной реализации ParameterizedType, но с помощью предыдущего механизма запись немножко короче и красивее. И да: "type token"-ы не нужны, если например информация о параметризации уже доступна, например, из типа поля в каком-нибудь классе (т.е., обычный private final Map<String, Float> map; уже содержит достаточно информации о типе (класс по прежнему -- просто Map)).
Результат вывода:
ok
1
179746 => 3239400
Может вам сначала получить название через строку и потом его использовать
int startIndex = getResponse.indexOf("\"data\": {")+9;
int endIndex = getResponse.indexOf("\": {", startIndex);
String nameAfterData = getResponse.subString(startIndex, endIndex);
и потом просто использовать имя JSON объекта пр парсинге?
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости