Gson 无法调用自定义序列化程序
Gson Failing to call custom Serializer
我一直在尝试按照 here 给出的建议关闭 Json 中表示的数值的科学记数法。我遇到的问题是我的自定义序列化程序从未被调用过。
我尝试了不同的代码变体,最终得到了:
public class TestExternaliser {
static class SpecialSerializer implements JsonSerializer<Object> {
@Override
public JsonElement serialize(Object x,
Type type,
JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive("xxx");
}
}
public static void main(String... args) {
JsonObject root = new JsonObject();
root.addProperty("String", "String");
root.addProperty("Num", Integer.valueOf(123));
root.addProperty("Bool", Boolean.TRUE);
Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(Object.class, new SpecialSerializer())
.setPrettyPrinting()
.create();
System.out.println(gson.toJson(root));
}
}
如果我对 API 的理解正确,那么此代码会对所有值使用自定义序列化,因此它应该为所有值生成 "xxx"
,但我一直得到的是:
{
"String": "String",
"Num": 123,
"Bool": true
}
怎么了?
在 playwright、一个微软库和 rust-rcon 库中,类似的事情发生在我身上。我离开你link.
出现此错误是因为您安装了jdk 11 或更高版本以及 2.8.6
之前的 gson
https://github.com/microsoft/playwright-java/issues/245#issuecomment-775351308
https://github.com/MrGraversen/rust-rcon/pull/2#event-4300625968
解决方案是使用最新版本的 gson,尽管该版本是他们使用的版本,但我将其添加到我的 POM 中以强制 maven 使其余依赖项使用最新版本。试试看告诉我!
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
试试这个解决方案 :D
What's going wrong?
由于 Gson 的设计限制,没有错:Object
和 JsonElement
类型适配器层次结构 cannot 被覆盖。
这是涵盖所有四个 object/number 层次结构和 value/JSON 树对的测试:
public final class LimitationsTest {
private static final JsonSerializer<Object> defaultJsonSerializer = (src, typeOfSrc, context) -> new JsonPrimitive("xxx");
private static final Gson objectDefaultsGson = new GsonBuilder()
.registerTypeHierarchyAdapter(Object.class, defaultJsonSerializer)
.create();
private static final Gson numberDefaultsGson = new GsonBuilder()
.registerTypeHierarchyAdapter(Number.class, defaultJsonSerializer)
.create();
private static final class Value {
@SerializedName("String")
private String string;
@SerializedName("Num")
private Number num;
@SerializedName("Bool")
private Boolean bool;
}
private static final Object object;
private static final JsonElement jsonElement;
static {
final Value newObject = new Value();
newObject.string = "String";
newObject.num = 123;
newObject.bool = Boolean.TRUE;
object = newObject;
final JsonObject newJsonElement = new JsonObject();
newJsonElement.addProperty("String", "String");
newJsonElement.addProperty("Num", 123);
newJsonElement.addProperty("Bool", Boolean.TRUE);
jsonElement = newJsonElement;
}
@Test
public void testObjectObject() {
Assertions.assertEquals("\"xxx\"", objectDefaultsGson.toJson(object));
}
@Test
public void testObjectJsonElement() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":123,\"Bool\":true}", objectDefaultsGson.toJson(jsonElement));
}
@Test
public void testNumberObject() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":\"xxx\",\"Bool\":true}", numberDefaultsGson.toJson(object));
}
@Test
public void testNumberJsonElement() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":123,\"Bool\":true}", numberDefaultsGson.toJson(jsonElement));
}
}
简而言之JsonElement
s被认为是已经序列化的,所以你要找的东西隐藏在testNumberObject
中:将Number
定义为超类(或Float
/Double
最精确),并序列化包含字段的对象,而不是 JsonElement
。如果您必须使用 JsonElement
,则将“格式良好”的值直接放入 Num
属性(BigDecimal
应该可以正常工作)。
更新 1.
@Test
public void testNoScientificNotationForJsonElement() {
final JsonObject newJsonElement = new JsonObject();
newJsonElement.addProperty("a", new BigDecimal(new BigDecimal("1E+10").toPlainString()));
newJsonElement.addProperty("b", new BigDecimal("1E+10") {
@Override
public String toString() {
return toPlainString();
}
});
final Gson gson = new Gson();
Assertions.assertEquals("{\"a\":10000000000,\"b\":10000000000}", gson.toJson(newJsonElement));
}
我一直在尝试按照 here 给出的建议关闭 Json 中表示的数值的科学记数法。我遇到的问题是我的自定义序列化程序从未被调用过。
我尝试了不同的代码变体,最终得到了:
public class TestExternaliser {
static class SpecialSerializer implements JsonSerializer<Object> {
@Override
public JsonElement serialize(Object x,
Type type,
JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive("xxx");
}
}
public static void main(String... args) {
JsonObject root = new JsonObject();
root.addProperty("String", "String");
root.addProperty("Num", Integer.valueOf(123));
root.addProperty("Bool", Boolean.TRUE);
Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(Object.class, new SpecialSerializer())
.setPrettyPrinting()
.create();
System.out.println(gson.toJson(root));
}
}
如果我对 API 的理解正确,那么此代码会对所有值使用自定义序列化,因此它应该为所有值生成 "xxx"
,但我一直得到的是:
{
"String": "String",
"Num": 123,
"Bool": true
}
怎么了?
在 playwright、一个微软库和 rust-rcon 库中,类似的事情发生在我身上。我离开你link.
出现此错误是因为您安装了jdk 11 或更高版本以及 2.8.6
之前的 gsonhttps://github.com/microsoft/playwright-java/issues/245#issuecomment-775351308 https://github.com/MrGraversen/rust-rcon/pull/2#event-4300625968
解决方案是使用最新版本的 gson,尽管该版本是他们使用的版本,但我将其添加到我的 POM 中以强制 maven 使其余依赖项使用最新版本。试试看告诉我!
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
试试这个解决方案 :D
What's going wrong?
由于 Gson 的设计限制,没有错:Object
和 JsonElement
类型适配器层次结构 cannot 被覆盖。
这是涵盖所有四个 object/number 层次结构和 value/JSON 树对的测试:
public final class LimitationsTest {
private static final JsonSerializer<Object> defaultJsonSerializer = (src, typeOfSrc, context) -> new JsonPrimitive("xxx");
private static final Gson objectDefaultsGson = new GsonBuilder()
.registerTypeHierarchyAdapter(Object.class, defaultJsonSerializer)
.create();
private static final Gson numberDefaultsGson = new GsonBuilder()
.registerTypeHierarchyAdapter(Number.class, defaultJsonSerializer)
.create();
private static final class Value {
@SerializedName("String")
private String string;
@SerializedName("Num")
private Number num;
@SerializedName("Bool")
private Boolean bool;
}
private static final Object object;
private static final JsonElement jsonElement;
static {
final Value newObject = new Value();
newObject.string = "String";
newObject.num = 123;
newObject.bool = Boolean.TRUE;
object = newObject;
final JsonObject newJsonElement = new JsonObject();
newJsonElement.addProperty("String", "String");
newJsonElement.addProperty("Num", 123);
newJsonElement.addProperty("Bool", Boolean.TRUE);
jsonElement = newJsonElement;
}
@Test
public void testObjectObject() {
Assertions.assertEquals("\"xxx\"", objectDefaultsGson.toJson(object));
}
@Test
public void testObjectJsonElement() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":123,\"Bool\":true}", objectDefaultsGson.toJson(jsonElement));
}
@Test
public void testNumberObject() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":\"xxx\",\"Bool\":true}", numberDefaultsGson.toJson(object));
}
@Test
public void testNumberJsonElement() {
Assertions.assertEquals("{\"String\":\"String\",\"Num\":123,\"Bool\":true}", numberDefaultsGson.toJson(jsonElement));
}
}
简而言之JsonElement
s被认为是已经序列化的,所以你要找的东西隐藏在testNumberObject
中:将Number
定义为超类(或Float
/Double
最精确),并序列化包含字段的对象,而不是 JsonElement
。如果您必须使用 JsonElement
,则将“格式良好”的值直接放入 Num
属性(BigDecimal
应该可以正常工作)。
更新 1.
@Test
public void testNoScientificNotationForJsonElement() {
final JsonObject newJsonElement = new JsonObject();
newJsonElement.addProperty("a", new BigDecimal(new BigDecimal("1E+10").toPlainString()));
newJsonElement.addProperty("b", new BigDecimal("1E+10") {
@Override
public String toString() {
return toPlainString();
}
});
final Gson gson = new Gson();
Assertions.assertEquals("{\"a\":10000000000,\"b\":10000000000}", gson.toJson(newJsonElement));
}