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

Can I override Gson's built-in number converters directly (not by delegation)?

我正在使用 Gson 将我的 JSON 数据转换为 Map<String, Object>。我的 JSON 有一些整数(实际上很长)字段,我希望它们被解析为很长(很明显)。但是,Gson 将它们解析为双打。我怎样才能让 Gson 将它们解析为 longs/integers?我已经看到 How to deserialize a list using GSON or another JSON library in Java? but I don't want to create a strongly-typed custom class, I'll be using a Map. I've also seen Android: Gson deserializes Integer as Double 和其他一些我认为可能重复的问题,但所有答案要么指向创建强类型 class,创建在反序列化中起作用的额外函数,要么完全使用另一个库。

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

更新: 尽管我已经解释得很清楚了,但有些人仍然不明白我 不是 这个简单的事实对于另一个库(例如杰克逊),我知道一个简单的事实,即任何解析器都应该能够将 2.0 识别为浮点数,将 2 识别为纯整数并进行相应的解析,所以请别指着我告诉 为什么 是这样,因为它根本不正确,并且不是不正确解析整数的借口。所以,不,这是 不是 Gson. Deserialize integers as integers and not as doubles 的副本。

你不能。

长答案

您不能覆盖 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 关于这个问题。