我可以直接覆盖 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
。但是没有 Double
或 Integer
或 Number
甚至 Object
。所以你不能覆盖它,除非你从更高的地方覆盖它,比如在处理 Map
时。还有 was answered on the thread you reference 关于这个问题。
我正在使用 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
。但是没有 Double
或 Integer
或 Number
甚至 Object
。所以你不能覆盖它,除非你从更高的地方覆盖它,比如在处理 Map
时。还有 was answered on the thread you reference 关于这个问题。