Gson. Десериализовать целые числа как целые числа, а не как двойные

У меня есть объект JSON с произвольными значениями внутри. И я хочу десериализовать это на карте. Все в порядке, кроме преобразования целых чисел в двойные. Смотрите пример:

{"id":1, "inner_obj":{"key":"value","num":666,"map":{"key":"value"}}}

десериализуется к этому (map.toString ()):

{id=1.0, inner_obj={key=value, num=666.0, map={key=value}}}

Есть ли какой-нибудь простой способ десериализации?Я бы" а также "Num» как целые числа, а не как двойники?

 Megakoresh12 авг. 2016 г., 12:52
Вопрос явно задан для реализации Gson. Пожалуйста, придерживайтесь вопроса.
 Tom Carchrae13 июн. 2013 г., 17:22
Джексон гораздо лучше справляется с определением типов карт, и его гораздо проще настроить, чем GSON:github.com/FasterXML/jackson-databind
 aditsu11 апр. 2017 г., 15:18
Также смэтот ответ Я написал для аналогичного вопроса; подвох в том, что вам придется анализировать данные какObject а затем бросить на все, что вам нужно

Ответы на вопрос(6)

В JSON нет целочисленного типа. 1 и 1.0 одинаковы. Вам нужно проанализировать это 1.0 к 1 в вашем коде. Или вам нужно сопоставить JSON с некоторым классом VO и явно определить тип полей класса, чтобы GSON мог понять, что вы ищете.

 John Vint13 июн. 2013 г., 19:28
@ Моисей определяет карту <String, Integer>
 Moses13 июн. 2013 г., 17:17
Но в Java есть целые и двойные числа. И это'легко десериализовать {"Num»: 1} к Integer, если у меня есть класс с полем Integer "Num», но когда gson десериализует JSON в Map <Строка, Объект> он решает использовать Double. Так что я'ищу способ отключить этот подход.
 Moses14 июн. 2013 г., 08:56
Карта должна содержать не только целые числа.

Я сам искал решение проблемы с вложенной картой и "이종은" выше был первый ответ, который фактически помог в нетривиальных случаях использования.

Поскольку вышеупомянутое решение обрабатывало только Number I, оно обновило решение, чтобы обеспечить возможность общего анализа для String и booleans, см. Обновленный код ниже:

private static class MapDeserializer implements JsonDeserializer {

    public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Map m = new LinkedHashMap();
        JsonObject jo = json.getAsJsonObject();
        for (Entry mx : jo.entrySet()) {
            String key = mx.getKey();
            JsonElement v = mx.getValue();
            if (v.isJsonArray()) {
                m.put(key, g.fromJson(v, List.class));
            } else if (v.isJsonPrimitive()) {
                Number num = null;
                ParsePosition position=new ParsePosition(0);
                String vString=v.getAsString();
                try {
                  num = NumberFormat.getInstance(Locale.ROOT).parse(vString,position);
                } catch (Exception e) {
                }
                //Check if the position corresponds to the length of the string
                if(position.getErrorIndex() < 0 && vString.length() == position.getIndex()) {
                  if (num != null) {
                    m.put(key, num);
                    continue;
                  }
                }
                JsonPrimitive prim = v.getAsJsonPrimitive();
                if (prim.isBoolean()) {
                    m.put(key, prim.getAsBoolean());
                } else if (prim.isString()) {
                    m.put(key, prim.getAsString());
                } else {
                    m.put(key, null);
                }

            } else if (v.isJsonObject()) {
                m.put(key, g.fromJson(v, Map.class));
            }

        }
        return m;
    }
}

private static class ListDeserializer implements JsonDeserializer {

    public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        List m = new ArrayList();
        JsonArray arr = json.getAsJsonArray();
        for (JsonElement jsonElement : arr) {
            if (jsonElement.isJsonObject()) {
                m.add(g.fromJson(jsonElement, Map.class));
            } else if (jsonElement.isJsonArray()) {
                m.add(g.fromJson(jsonElement, List.class));
            } else if (jsonElement.isJsonPrimitive()) {
                Number num = null;
                try {
                    num = NumberFormat.getInstance().parse(jsonElement.getAsString());
                } catch (Exception e) {
                }
                if (num != null) {
                    m.add(num);
                    continue;
                }
                JsonPrimitive prim = jsonElement.getAsJsonPrimitive();
                if (prim.isBoolean()) {
                    m.add(prim.getAsBoolean());
                } else if (prim.isString()) {
                    m.add(prim.getAsString());
                } else {
                    m.add(null);
                }
            }
        }
        return m;
    }
}

private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").create();
 peanutman20 нояб. 2017 г., 12:28
Это мне очень помогло! Я просто хотел бы указать на небольшую ошибку. В ListDeserializer вы должны удалить "m.add (NUM)» в блоке try {}, потому что он все равно будет добавлен после try / catch. Если вы используете код как есть, он добавит каждое число к результату дважды.
 David16 февр. 2018 г., 01:25
Я думаю, что вы можете заменить вызовы g.fromJson (...) на context.deserialize (...), чтобы избежать необходимости в статическом экземпляре gson (по крайней мере, он работает для меня для gson 2.6.2)
 Erik Calissendorff22 нояб. 2017 г., 09:28
Спасибо, обновили пример сейчас.

Чтобы избежать возможного исключения ClassCastException, лучше привести кNumber первый. В следующем кодеmap был десериализован из JSON какMap без дженериков.

int numberOfPages = ((Number) map.get("number_of_pages")).intValue();

JSON имеет только один тип Number, и синтаксический анализатор не может автоматически определить, к какому типу его преобразовать.

Если ты нене собираюсь использовать строго типизированный граф объектов, рассмотрите возможность использованияJsonElement типы:

JsonObject root = new Gson().fromJson(json, JsonObject.class);
int num = root.getAsJsonObject("inner_obj").get("num").getAsInt();

Вот мой пример, первая часть - это определение класса, имеющего поле типа int.

import com.google.api.client.util.Key;

public class Folder {

    public static final String FIELD_NAME_CHILD_COUNT = "childCount";

    @Key(FIELD_NAME_CHILD_COUNT)
    public final int childCount;

    public Folder(int aChildCount) {
        childCount = aChildCount;
    }
}

Затем TypeAdapter для преобразования числового типа в Gson в объект Java.

GsonBuilder gsb = new GsonBuilder();

gsb.registerTypeAdapter(Folder.class, new JsonDeserializer() {

            @Override
            public Folder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

                int value = json.getAsJsonObject().get("childCount").getAsJsonPrimitive().getAsInt();

                return new Folder(value);

            }
        }
);

Третья часть - это тестовые данные, и это работает.

String gsonData =  new String("\"folder\":{\"childCount\":0}");

Это'мой код

private static class MapDeserializer implements JsonDeserializer {
    public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  throws JsonParseException {
        Map m  = new LinkedHashMap();
        JsonObject jo = json.getAsJsonObject();
        for (Entry  mx : jo.entrySet()){
            String key = mx.getKey();
            JsonElement v = mx.getValue();
            if(v.isJsonArray()){
                m.put(key, g.fromJson(v, List.class));
            }else if(v.isJsonPrimitive()){
                 Number num = null;
                  try {
                      num = NumberFormat.getInstance().parse(v.getAsString());
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                m.put(key,num);
            }else if(v.isJsonObject()){
                m.put(key,g.fromJson(v, Map.class));    
            }

        }
      return m;
   }
}

private static class ListDeserializer implements JsonDeserializer {
    public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  throws JsonParseException {
        List m  = new ArrayList();
        JsonArray arr = json.getAsJsonArray();
        for (JsonElement jsonElement : arr) {
            if(jsonElement.isJsonObject()){
                m.add(g.fromJson(jsonElement, Map.class));
            }else if(jsonElement.isJsonArray()){
                m.add(g.fromJson(jsonElement, List.class));
            }else if(jsonElement.isJsonPrimitive()){
                Number num = null;
                try {
                  num = NumberFormat.getInstance().parse(jsonElement.getAsString());
                } catch (Exception e) {
                }
                m.add(num);
            }
        }
      return m;
   }
}

private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();

Ваш ответ на вопрос