【问题标题】:Can I override Gson's built-in number converters directly (not by delegation)?我可以直接覆盖 Gson 的内置数字转换器(而不是通过委托)吗?
【发布时间】:2016-07-31 10:28:36
【问题描述】:

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

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

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

【问题讨论】:

  • 可能重复Gson. Deserialize integers as integers and not as doubles 这个问题有一个关于为什么的答案和一个替代来使用Jackson
  • FWIW,Square 的 Moshi 似乎默认为与 Gson 相同的行为:当被要求输入 JsonAdapter<Map<String, Object>> adapter = moshi.adapter(Types.newParameterizedType(Map.class, String.class, Object.class)) 时,适配器会将“1000”解析为 Double 1000.0
  • @Yazan 我已经明确表示我不想使用另一个库并使用 Gson,任何足够体面的库都应该能够区分 2.02 作为浮点数和整数,因此对 why 的回答是无关紧要的。我已经阅读了这个问题,这是 not 重复的。如果使用 Gson 本身无法做到这一点,那么答案将是 no
  • 好吧,我记得最后一件事是你的标题是Why does Gson deserialize my JSON's integer fields as Double 为什么 我发布的问题清楚地说明了为什么,不是无关紧要,如果可以的话,JSON 没有整数类型只有双'不理解或不接受,这是你的问题
  • @Yazan 不是我更改了标题,而是其他人编辑了它。我至少和你一样明白这意味着什么,别担心。无论如何它仍然不相关。

标签: json gson deserialization json-deserialization


【解决方案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&lt;&gt; 事物和基本 String。但没有DoubleIntegerNumber 甚至Object。所以你不能覆盖它,除非你从更高的地方覆盖它,比如处理Map。还有那个问题was answered on the thread you reference

【讨论】:

  • 谢谢,我想我会试试这个,如果我需要更多转换器,只需使用相同的模式,或者如果我搞砸了,我想我会选择另一个库作为最终选择。
猜你喜欢
  • 1970-01-01
  • 2014-08-18
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多