gson 将整数反序列化为整数而不是双精度数

igsr9ssn  于 2022-11-23  发布在  其他
关注(0)|答案(8)|浏览(210)

我有一个里面有任意值的json对象。我想在Map中反序列化它。除了将整数转换为双精度数外,一切都可以。参见示例:

{"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}}}

是否有简单的方法将“id”和“num”反序列化为Integers而不是Double?

rmbxnbpk

rmbxnbpk1#

JSON中没有整数类型,1和1.0是一样的,你需要在代码中把1.0解析成1,或者你需要把JSONMap到某个VO类,显式定义该类的字段类型,这样GSON就能理解你要找的东西。

xt0899hw

xt0899hw2#

我自己一直在寻找嵌套Map问题的解决方案,上面的""是第一个在非平凡用例中实际上有帮助的答案。
由于上面的解决方案只处理了第一个问题,因此更新了解决方案以提供String和布尔值的通用解析功能,请参见下面的更新代码:

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();
wlzqhblo

wlzqhblo3#

JSON只有一个Number类型,解析器无法自动判断要将其转换为什么类型。
如果你不打算使用强类型对象图,考虑使用JsonElement类型:

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

new9mtju4#

这是我的准则

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();
kt06eoxx

kt06eoxx5#

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

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

w7t8yxp56#

下面是我的例子,第一部分是类的定义,这个类有一个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<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);

            }
        }
);

第三部分是测试数据,它工作。

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

2jcobegt7#

寄存器类型适配器为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();

并使用它进行反序列化,如下所示:gson.fromJson(instanceJson, Map.class),其中instanceJson是应该反序列化为Map对象的json

luaexgnf

luaexgnf8#

这是我解决这个问题的方法。2我试着尽可能简洁地实现它。3我没有找到一个更好的简单的方法来检查一个数是否是整数。

public final class GSONUtil {

    private GSONUtil() {
    }

    public static Gson createGson() {

        // @formatter:off
        return new GsonBuilder()
                .registerTypeAdapter(Map.class, createMapDeserializer())
                .registerTypeAdapter(List.class, createListDeserializer())
                .create();
        // @formatter:on
    }

    private static JsonDeserializer<Map<String,Object>> createMapDeserializer() {
        return new JsonDeserializer<Map<String,Object>>() {

            @Override
            public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                    throws JsonParseException {

                return json.getAsJsonObject().entrySet().stream() // stream
                        .collect(Collectors.toMap(Entry::getKey, (e) -> JSONUtil.deserialize(e.getValue(), context)));
            }
        };
    }

    private static JsonDeserializer<List<Object>> createListDeserializer() {
        return new JsonDeserializer<List<Object>>() {

            @Override
            public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                    throws JsonParseException {

                return StreamSupport.stream(json.getAsJsonArray().spliterator(), false) // stream
                        .map((e) -> JSONUtil.deserialize(e, context)).collect(Collectors.toList());
            }
        };
    }

    private static Object deserialize(JsonElement value, JsonDeserializationContext context) {

        if (value.isJsonNull()) {
            return null;
        }
        if (value.isJsonObject()) {
            return context.deserialize(value, Map.class);
        }
        if (value.isJsonArray()) {
            return context.deserialize(value, List.class);
        }
        if (value.isJsonPrimitive()) {
            return parsePrimitive(value);
        }

        throw new IllegalStateException("This exception should never be thrown!");
    }

    private static Object parsePrimitive(JsonElement value) {

        final JsonPrimitive jsonPrimitive = value.getAsJsonPrimitive();

        if (jsonPrimitive.isString()) {
            return jsonPrimitive.getAsString();
        }

        if (jsonPrimitive.isBoolean()) {
            return jsonPrimitive.getAsBoolean();
        }

        if (jsonPrimitive.isNumber()) {
            return parseNumber(jsonPrimitive);
        }

        throw new IllegalStateException("This exception should never be thrown!");
    }

    private static Number parseNumber(JsonPrimitive jsonPrimitive) {

        if (isInteger(jsonPrimitive)) {
            return jsonPrimitive.getAsLong();
        }

        return jsonPrimitive.getAsDouble();
    }

    private static boolean isInteger(final JsonPrimitive jsonPrimitive) {
        return jsonPrimitive.getAsString().matches("[-]?\\d+");
    }
}

相关问题