Подтвердить что ты не робот

Пропустить корневой элемент при десериализации json

Как я должен десериализовать следующий JSON, чтобы пропустить корневой элемент и проанализировать только внутреннюю часть этого JSON. Я хотел бы избежать создания дополнительного 3-го класса Root, который будет включать только поле MapWrapper.

{
    "root": {
        "language": "en",
        "map": {
            "k1": {
                "name": "n1",
            },
            "k2": {
                "name": "n2",
            }
        }
    }
}

Поэтому мне бы хотелось иметь только эти два класса:

class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;
}

class MyMapEntry {
    String name;
}
4b9b3361

Ответ 1

вы можете использовать GSON Library для этого.

Ниже код поможет решить вашу проблему.

public class ConvertJsonToObject {

    private static Gson gson = new GsonBuilder().create();

    public static final <T> T getFromJSON(String json, Class<T> clazz) {
        return gson.fromJson(json, clazz);
    }

    public static final <T> String toJSON(T clazz) {
        return gson.toJson(clazz);
    }
}

String json; // your jsonString
Map<String,Object> r = ConvertJsonToObject.getFromJSON(json,Map.class);
String innerJson = ConvertJsonToObject.toJson(r.get("root"));
MapWrapper _r = ConvertJsonToObject.getFromJSON(innerJson,MapWrapper.class);

Ответ 2

Это оптимальный код для этого за один проход.

MapWrapper класс

public class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;

    public MapWrapper(String language, Map<String, MyMapEntry> map) {
        this.language = language;
        this.map = map;
    }
}

MyMapEntry класс

public class MyMapEntry {

    String name;

    public MyMapEntry(String name) {
        this.name = name;
    }
}

Пользовательский десериализатор

public class MyDeserialiser  implements JsonDeserializer<MapWrapper>
{

    @Override
    public MapWrapper deserialize(JsonElement json, Type typeOfT,
        JsonDeserializationContext ctx) throws JsonParseException {

        JsonObject _global = json.getAsJsonObject();
        _global = _global.get("root").getAsJsonObject();

        JsonPrimitive lang = (JsonPrimitive) _global.get("language");
        JsonElement map = _global.get("map");
        Map<String, MyMapEntry> inMap = new LinkedHashMap<String, MyMapEntry>();
        for (Entry<String, JsonElement> entry : map.getAsJsonObject()
                .entrySet()) {
            MyMapEntry _m = new MyMapEntry(entry.getValue().toString());
            inMap.put(entry.getKey(), _m);
        }
        return new MapWrapper(lang.getAsString(), inMap);
    }   
}

Зарегистрируйте его с помощью GSON

new GsonBuilder().registerTypeAdapter(MapWrapper.class,new MyDeserialiser()).create()

Теперь десериализуем следующий код

String json; // your jsonString
MapWrapper result = ConvertJsonToObject.getFromJSON(json,MapWrapper.class);

Ответ 3

Мой ответ опоздал на эту вечеринку.

Как только мы разобраем Json, контейнер всегда будет подклассом JsonObject JsonElement. Таким образом, если мы хотим пропустить его, нам просто нужно отнести его в свой подкласс и захватить поле, удерживающее наш внутренний класс.

    String response = ....;

    Gson gson = new Gson();

    JsonParser p = new JsonParser();
    JsonElement jsonContainer = p.parse(response);
    JsonElement jsonQuery = ((JsonObject) jsonContainer).get("query");

    MyQuery query = gson.fromJson(jsonQuery, MyQuery.class);

Примечание. JsonObject и JSONObject - это разные классы (используйте импорт com.google.Json).

Вы могли бы обобщить этот ответ больше, чтобы вам не нужно было знать имя внутреннего класса. Вы сделали бы это, просто получив одно и то же поле объекта контейнера. Тем не менее, я не вижу возможности сделать это, кроме запуска итератора, нет метода getValue (atIndex), который я могу видеть, и я думаю, что запуск итератора, вероятно, менее эффективен, чем просто поиск поля по имени (но может быть неправильно).

Метод итератора выглядит следующим образом:

    JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator()
                            .next().getValue();

Ответ 4

Рассмотрим следующий JSON:

{"authorization":{"username":"userabc", "password":"passabc"}}

DTO для этого JSON без корневого элемента

public class Authorization {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // Add a container for the root element
    public static class Container {
        public Authorization authorization;
    }
}

Преобразуйте из/в JSON, используя следующие методы (вы можете сохранить это в DTO или в каком-либо другом классе справки)

public String toJson(Authorization authorization) {
    Gson gson = new Gson();
    Authorization.Container container = new Authorization.Container();
    container.authorization = authorization;
    return gson.toJson(container);
}

public Authorization fromJson(String json) {
    Gson gson = new Gson();
    Authorization.Container container = gson.fromJson(json, Authorization.Container.class);
    return container.authorization;
}

Ответ 5

Вы можете десериализовать его в Map<String, MapWrapper>.

Ответ 6

Вдохновленный идеей Густава Карлсона, я решил расширить его до конкретного образца. Здесь junit-тест, который анализирует синтаксический анализ этого JSON как карты.

public static class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;
}

public static class MyMapEntry {
    String name;
}

@Test
public void testParsing() {
    String json = "{\n" +
            "    \"root\": {\n" +
            "        \"language\": \"en\",\n" +
            "        \"map\": {\n" +
            "            \"k1\": {\n" +
            "                \"name\": \"n1\"\n" +
            "            },\n" +
            "            \"k2\": {\n" +
            "                \"name\": \"n2\"\n" +
            "            }\n" +
            "        }\n" +
            "    }\n" +
            "}";
    Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
    Type type = new TypeToken<Map<String, MapWrapper>>(){}.getType();
    Map<String, MapWrapper> parsed = gson.fromJson(json, type);
    MapWrapper mapWrapper = parsed.get("root");
    Assert.assertEquals("en", mapWrapper.language);
    Assert.assertEquals("n2", mapWrapper.map.get("k2").name);
}