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

时间:2013-06-13 15:07:41

标签: java json gson

我的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”反序列化为整数而不是双打?

8 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:1)

这是我的代码

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

答案 3 :(得分:1)

我自己和#34;이종은&#​​34;正在寻找嵌套地图问题的解决方案。上面是第一个真正有助于非平凡用例的答案。

由于上面的解决方案只处理了Number I更新了解决方案,以便为String和booleans提供通用的解析功能,请参阅下面的更新代码:

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

答案 4 :(得分: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}");

答案 5 :(得分:0)

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

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

答案 6 :(得分: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是对象的json,应反序列化为Map

答案 7 :(得分: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+");
    }
}