java 格森。将整数反序列化为整数而不是双精度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17090589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:56:25  来源:igfitidea点击:

Gson. Deserialize integers as integers and not as doubles

javajsongson

提问by Moses

I have json object with arbitary values inside. And I want to deserialize it in a Map. Everything is ok except converting integers to a doubles. See example:

我有一个带有任意值的 json 对象。我想在地图中反序列化它。除了将整数转换为双精度数外,一切正常。见示例:

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

deserializes to this(map.toString()):

反序列化为 this(map.toString()):

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

Is there some easy way to deserialize "id" and "num" as Integers and not as Doubles?

是否有一些简单的方法可以将“id”和“num”反序列化为整数而不是双精度数?

回答by NINCOMPOOP

There are no integer type in JSON. 1 and 1.0 are the same. You need to parse that 1.0 to 1 in your code. Or you need to map the JSON to some VO class and define the type of fields of the class explicitly , so that GSON can understand what you are looking for.

JSON 中没有整数类型。1 和 1.0 是一样的。您需要在代码中将 1.0 解析为 1。或者你需要将 JSON 映射到某个 VO 类并明确定义该类的字段类型,以便 GSON 可以理解您要查找的内容。

回答by McDowell

JSON only has a single Number type and there is no way for the parser to automatically tell what type to convert it to.

JSON 只有一个 Number 类型,解析器无法自动告诉将它转换为什么类型。

If you aren't going to use a strongly typed object graph, consider using the JsonElementtypes:

如果您不打算使用强类型对象图,请考虑使用JsonElement类型:

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

回答by Erik Calissendorff

Been searching for a solution to the nested Map problem myself and "???" above was the first answer that actually helped in the non trivial use cases.

我自己和“???”一直在寻找嵌套 Map 问题的解决方案 上面是第一个在非平凡用例中真正有帮助的答案。

Since the solution above only handled Number I updated the solution to provide generic parsing capability for String and booleans also, see the updated code below:

由于上面的解决方案只处理数字,我更新了解决方案以提供字符串和布尔值的通用解析功能,请参阅下面的更新代码:

private static class MapDeserializer implements JsonDeserializer<Map<String, Object>> {

    public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        JsonObject jo = json.getAsJsonObject();
        for (Entry<String, JsonElement> 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<List<Object>> {

    public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        List<Object> m = new ArrayList<Object>();
        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();

回答by hrzafer

To avoid possible ClassCastException, it is better to cast to Numberfirst. In the following code mapwas deserialized from JSON as a Mapwith no generics.

为避免可能出现的 ClassCastException,最好先强制转换Number。在以下代码中map,从 JSON 反序列化为Map没有泛型的 a。

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

回答by ???

It's my code

这是我的代码

private static class MapDeserializer implements JsonDeserializer<Map<String,Object>> {
    public Map<String,Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  throws JsonParseException {
        Map<String,Object> m  = new LinkedHashMap<String, Object>();
        JsonObject jo = json.getAsJsonObject();
        for (Entry<String, JsonElement>  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<List<Object>> {
    public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  throws JsonParseException {
        List<Object> m  = new ArrayList<Object>();
        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();

回答by Oleksandr Tsurika

Register type adapter for Map:

注册类型适配器Map

   Gson gson = new GsonBuilder()
            .registerTypeAdapter(Map.class, new JsonDeserializer<Map>() {
                @Override
                public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    LinkedTreeMap<String,Object> m  = new LinkedTreeMap<String, Object>();
                    JsonObject jo = json.getAsJsonObject();
                    for (Map.Entry<String, JsonElement> mx : jo.entrySet()){
                        String key = mx.getKey();
                        JsonElement v = mx.getValue();
                        if(v.isJsonArray()){
                            m.put(key, context.deserialize(v, List.class));
                        }else if(v.isJsonPrimitive()){
                            Object value = v.getAsString();
                            try {
                                Object numValue = NumberFormat.getInstance().parse((String)value);
                                if (numValue != null && numValue.toString().equals(value)) {
                                    value = numValue;
                                }
                            } catch (Exception e) {
                            }
                            m.put(key, value);
                        }else if(v.isJsonObject()){
                            m.put(key,context.deserialize(v, Map.class));
                        }
                    }
                    return m;
                }
            })
            .create();

and deserialize using it like: gson.fromJson(instanceJson, Map.class), where instanceJsonis an jsonof object which should be deserialized into Map.

并使用它进行反序列化,例如:gson.fromJson(instanceJson, Map.class),其中instanceJsonjson应反序列化为Map.

回答by Zephyr

Here is my example, the first part is the definition of the class that has an int type field.

这是我的示例,第一部分是具有 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;
    }
}

Then the TypeAdapter to convert the number type in Gson to a Java object.

然后 TypeAdapter 将 Gson 中的数字类型转换为 Java 对象。

GsonBuilder gsb = new GsonBuilder();

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

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

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

                return new Folder(value);

            }
        }
);

The third part is the test data, and it works.

第三部分是测试数据,它起作用了。

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