18

我有 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}}}

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

4

8 回答 8

8

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

于 2013-06-13T15:11:35.387 回答
4

我自己一直在寻找嵌套地图问题的解决方案,上面的“이종은”是第一个真正有助于非平凡用例的答案。

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

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();
于 2015-08-26T20:04:05.853 回答
3

JSON 只有一个数字类型,解析器无法自动判断将其转换为哪种类型。

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

JsonObject root = new Gson().fromJson(json, JsonObject.class);
int num = root.getAsJsonObject("inner_obj").get("num").getAsInt();
于 2013-06-13T15:21:04.307 回答
2

这是我的代码

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();
于 2015-01-12T09:29:12.740 回答
1

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

int numberOfPages = ((Number) map.get("number_of_pages")).intValue();
于 2018-02-08T00:06:15.343 回答
0

注册类型适配器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对象。jsonMap

于 2019-11-26T19:41:43.283 回答
0

这是我的示例,第一部分是具有 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}");
于 2015-09-03T15:39:31.340 回答
0

这是我解决问题的解决方案。我试图尽可能干净地实现它。我没有找到更好的简单解决方案来检查数字是否为整数。

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+");
    }
}
于 2021-04-09T15:45:07.403 回答