让Gson解析整数而不是浮点数

时间:2016-08-10 08:11:24

标签: java json gson

我试图让Gson解析没有浮点值的值为Longs而不是默认情况下的双打值:

Gson gson = new GsonBuilder()
            .registerTypeAdapter(Object.class, (JsonDeserializer<Object>) (json, type, context) -> {
                // we don't want integer values to be parsed as floats
                String value = json.getAsJsonPrimitive().getAsString();
                if (value.matches("\\d+")) {
                    return Long.valueOf(value);
                } else {
                    return context.deserialize(json, type);
                }
            }).create();
...
gson.fromJson(payload);

我只想测试,天气包含.的值,如果没有,请将其解析为Long。否则使用默认解析方法。

然而,当我放置断点时,永远不会调用该方法。我想我以错误的方式注册了适配器。

EDIT1:Json可能包含包含字符串,整数,双精度和地图的列表。我需要一个通用的解决方案。

EDIT2:我也试过各种.registerTypeAdapter(Number.class.registerTypeAdapter(Double.class但没有效果。还没有打电话。

1 个答案:

答案 0 :(得分:0)

我找不到比完全覆盖Gson功能更好的方法。这是一个非常黑客,但没有其他解决方案似乎解决了这个问题:

public class Gson {

    private static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
        public <T> TypeAdapter<T> create(com.google.gson.Gson gson, TypeToken<T> type) {
            return type.getRawType() == Object.class ? (TypeAdapter<T>) new LongObjectTypeAdapter(gson) : null;
        }
    };



    static {
        try {
            Field field = ObjectTypeAdapter.class.getDeclaredField("FACTORY");

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

            field.setAccessible(true);
            field.set(null, FACTORY);

        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }



    private com.google.gson.Gson gson = new com.google.gson.Gson();



    public <T> T fromJson(String payload, Class<T> c) {
        return gson.fromJson(payload, c);
    }



    public String toJson(Object object) {
        return gson.toJson(object);
    }



    public static class LongObjectTypeAdapter extends TypeAdapter<Object> {

        private com.google.gson.Gson gson;

        public LongObjectTypeAdapter(com.google.gson.Gson gson) {
            this.gson = gson;
        }

        public Object read(JsonReader in) throws IOException {
            JsonToken token = in.peek();

            switch (token) {
                case BEGIN_ARRAY:
                    ArrayList list = new ArrayList();
                    in.beginArray();

                    while(in.hasNext()) {
                        list.add(this.read(in));
                    }

                    in.endArray();
                    return list;
                case BEGIN_OBJECT:
                    LinkedTreeMap map = new LinkedTreeMap();
                    in.beginObject();

                    while(in.hasNext()) {
                        map.put(in.nextName(), this.read(in));
                    }

                    in.endObject();
                    return map;
                case STRING:
                    return in.nextString();
                case NUMBER:
                    String value = in.nextString();
                    if (value.contains(".")) {
                        return Double.valueOf(value);
                    } else {
                        return Long.valueOf(value);
                    }

                case BOOLEAN:
                    return Boolean.valueOf(in.nextBoolean());
                case NULL:
                    in.nextNull();
                    return null;
                default:
                    throw new IllegalStateException();
            }
        }

        public void write(JsonWriter out, Object value) throws IOException {
            if (value == null) {
                out.nullValue();
            } else {
                TypeAdapter typeAdapter = gson.getAdapter(value.getClass());
                if (typeAdapter instanceof LongObjectTypeAdapter) {
                    out.beginObject();
                    out.endObject();
                } else {
                    typeAdapter.write(out, value);
                }
            }
        }
    }
}