我可以直接覆盖Gson的内置数字转换器(不是通过委托)吗?

时间:2016-04-10 10:44:47

标签: json gson deserialization json-deserialization

我正在使用Gson将我的JSON数据转换为Map<String, Object>。我的JSON有一些整数(实际上很长)字段,我希望它们被解析得很久(显然)。然而,Gson将它们解析为双打。我如何让Gson将它们解析为long / integers?我见过How to deserialize a list using GSON or another JSON library in Java?但我不想创建一个强类型的自定义类,我将使用Map。我还看到了Android: Gson deserializes Integer as Double以及其他一些我认为可能重复的问题,但所有答案都指向创建一个强类型类,创建在反序列化中起作用的额外函数或完全使用另一个函数库。

谷歌自己的JSON序列化器/反序列化器中是不是有一种简单的方法可以简单地将整数反序列化(是的,一个数字而不是一个点)作为一个整数而不是两倍,因为它应该首先作为默认值?如果我想发送浮点数,我将从服务器JSON发送2.0,而不是2。为什么在地球上我得到一个双倍,我该如何摆脱它?

更新尽管我已经清楚地解释过,但有些人仍然不理解我的另一个图书馆(例如杰克逊)和我知道一个简单的事实,即任何解析器都应该能够将2.0标识为浮点数并将2标识为纯整数并进行相应的解析,所以请不要指示我告诉为什么就是这样,因为它只是不正确,并不是不正确解析整数的借口。所以,不,这是重复Gson. Deserialize integers as integers and not as doubles

1 个答案:

答案 0 :(得分:1)

你不能。

答案很长

您无法覆盖gson的内置数字转换器。

我做了一个简短的代码测试,以便在gson试图找到委托转换器的引擎盖下查看。

package net.sargue.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.intellij.lang.annotations.Language;

import java.io.IOException;
import java.util.Map;

public class SO36528727 {
  public static void main(String[] args) {
    @Language("JSON")
    String json = "{\n" +
            "  \"anInteger\": 2,\n" +
            "  \"aDouble\": 2.0\n" +
            "}";

    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new LongDeserializerFactory())
            .create();
    Map<String, Object> m =
            gson.fromJson(json,
                          new TypeToken<Map<String, Object>>() {}.getType());

    System.out.println(m.get("aDouble").getClass());
    System.out.println(m.get("anInteger").getClass());
  }

  private static class LongDeserializerFactory
          implements TypeAdapterFactory
  {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      System.out.println("type = " + type);

      if (type.getRawType().equals(String.class)) {
        TypeAdapter<String> stringAdapter =
                gson.getDelegateAdapter(this, TypeToken.get(String.class));
        return new TypeAdapter<T>() {
          @Override
          public void write(JsonWriter out, T value) throws IOException {
            stringAdapter.write(out, (String) value);
          }

          @SuppressWarnings("unchecked")
          @Override
          public T read(JsonReader in) throws IOException {
            String s = stringAdapter.read(in);
            System.out.println("s = " + s);
            return (T) s;
          }
        };
      } else
        return null;
    }
  }
}

执行结果如下:

type = java.util.Map<java.lang.String, java.lang.Object>
type = java.lang.String
s = anInteger
s = aDouble
class java.lang.Double
class java.lang.Double

所以,你可以看到gson看起来只是两个转换器:整个Map<>的东西和基本的String。但不是DoubleIntegerNumber甚至Object。所以你可以覆盖它,除非你从更高的地方覆盖它,就像处理Map时一样。关于这个问题was answered on the thread you reference