javax.json serializer/deserializer 对于 Gson
javax.json serializer/deserializer for Gson
我正在尝试为 java.javax.JsonObject
s 写一个通用的 Gson serializer/deserializer:
public static class JavaxJsonObjConverter implements JsonSerializer<JsonObject>, JsonDeserializer<JsonObject> {
@Override
public JsonObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return JsonUtils.getJsonObjectFromString(json.toString());
}
@Override
public JsonElement serialize(JsonObject src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonParser().parse(src.toString());
}
}
当我尝试序列化 java.json.JsonObject
时,出现此错误:
Exception in thread "main" java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to javax.json.JsonObject
at om.headlandstech.utils.gson_utils.GsonUtils$JavaxJsonValueConverter.serialize(>GsonUtils.java:1)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapte>rFactory.java:208)
at ....
如果您也 post javax.json.JsonObject
实例(它们的构建方式),那就更好了。因为:最接近我可以重现它的是以下内容:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(JsonObject.class, new JavaxJsonObjConverter())
.create();
final JsonObject src = Json.createObjectBuilder()
.add("foo", "bar")
.build();
System.out.println(gson.toJson(src.get("foo"), JsonObject.class));
异常:
Exception in thread "main" java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to javax.json.JsonObject
at q43376802.Q43376802$JavaxJsonObjConverter.serialize(Q43376802.java:29)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.Gson.toJson(Gson.java:669)
at com.google.gson.Gson.toJson(Gson.java:648)
at com.google.gson.Gson.toJson(Gson.java:603)
at q43376802.Q43376802.main(Q43376802.java:26)
接下来。您的 JavaxJsonObjConverter
实现了 javax.json.JavaObject
(反)序列化器,但 javax.json.JavaObject
不是 javax.json
中 JSON 对象的根。层次结构根是 JsonValue
。所以你的(反)序列化器必须处理 JsonValue
而不是 JsonObject
。
public static class JavaxJsonValConverter
implements JsonSerializer<JsonValue> {
@Override
public JsonElement serialize(final JsonValue jsonValue, final Type type, final JsonSerializationContext context) {
return new JsonParser().parse(jsonValue.toString());
}
}
并通过删除和完全删除 JavaxJsonObjConverter
来注册它:
.registerTypeAdapter(JsonValue.class, new JavaxJsonValConverter())
然而,上面的序列化器是天真的,需要更多的资源,但是,给你一些灵活性(当 reading/writing 直接 from/to JSON 流可能太不合理(比较 DOM 和 XML 中的 SAX -- 这是同一个故事)):
JsonSerializer
和 JsonDeserializer
依赖 JSON 用 JsonElement
实现的树模型表示。这意味着必须将 entire JSON 加载到内存中,并且必须先构建其树模型,然后才能使用它。如果您要处理的 JSON 个对象很大,这将消耗更多内存。
toString()
也是一个糟糕的选择:它需要先生成内部字符串,从而再次消耗内存。
所以,上面的项目可能会非常大 内存打印。为了节省内存资源,您可以创建一个可以与 JSON 流一起工作的 Gson TypeAdapter
(这是 JSON 中每个(反)序列化器的基础)。
final class JsonValueTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> jsonValueTypeAdapter = new JsonValueTypeAdapter();
private JsonValueTypeAdapter() {
}
static TypeAdapter<JsonValue> getJsonValueTypeAdapter() {
return jsonValueTypeAdapter;
}
@Override
public void write(final JsonWriter out, final JsonValue jsonValue)
throws IOException {
final ValueType valueType = jsonValue.getValueType();
switch ( valueType ) {
case ARRAY:
JsonArrayTypeAdapter.instance.write(out, (JsonArray) jsonValue);
break;
case OBJECT:
JsonObjectTypeAdapter.instance.write(out, (JsonObject) jsonValue);
break;
case STRING:
JsonStringTypeAdapter.instance.write(out, (JsonString) jsonValue);
break;
case NUMBER:
JsonNumberTypeAdapter.instance.write(out, (JsonNumber) jsonValue);
break;
case TRUE:
JsonBooleanTypeAdapter.instance.write(out, jsonValue);
break;
case FALSE:
JsonBooleanTypeAdapter.instance.write(out, jsonValue);
break;
case NULL:
JsonNullTypeAdapter.instance.write(out, jsonValue);
break;
default:
throw new AssertionError(valueType);
}
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
final JsonToken jsonToken = in.peek();
switch ( jsonToken ) {
case BEGIN_ARRAY:
return JsonArrayTypeAdapter.instance.read(in);
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
return JsonObjectTypeAdapter.instance.read(in);
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
return JsonStringTypeAdapter.instance.read(in);
case NUMBER:
return JsonNumberTypeAdapter.instance.read(in);
case BOOLEAN:
return JsonBooleanTypeAdapter.instance.read(in);
case NULL:
return JsonNullTypeAdapter.instance.read(in);
case END_DOCUMENT:
throw new AssertionError("Must never happen");
default:
throw new AssertionError(jsonToken);
}
}
private static final class JsonNullTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> instance = new JsonNullTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonValue jsonNull)
throws IOException {
out.nullValue();
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
in.nextNull();
return JsonValue.NULL;
}
}
private static final class JsonBooleanTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> instance = new JsonBooleanTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonValue jsonBoolean)
throws IllegalArgumentException, IOException {
final ValueType valueType = jsonBoolean.getValueType();
switch ( valueType ) {
case TRUE:
out.value(true);
break;
case FALSE:
out.value(false);
break;
case ARRAY:
case OBJECT:
case STRING:
case NUMBER:
case NULL:
throw new IllegalArgumentException("Not a boolean: " + valueType);
default:
throw new AssertionError(jsonBoolean.getValueType());
}
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
return in.nextBoolean() ? JsonValue.TRUE : JsonValue.FALSE;
}
}
private static final class JsonNumberTypeAdapter
extends TypeAdapter<JsonNumber> {
private static final TypeAdapter<JsonNumber> instance = new JsonNumberTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonNumber jsonNumber)
throws IOException {
if ( jsonNumber.isIntegral() ) {
out.value(jsonNumber.longValue());
} else {
out.value(jsonNumber.doubleValue());
}
}
@Override
public JsonNumber read(final JsonReader in)
throws IOException {
// TODO is there a good way to instantiate a JsonNumber instance?
return (JsonNumber) Json.createArrayBuilder()
.add(in.nextDouble())
.build()
.get(0);
}
}
private static final class JsonStringTypeAdapter
extends TypeAdapter<JsonString> {
private static final TypeAdapter<JsonString> instance = new JsonStringTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonString jsonString)
throws IOException {
out.value(jsonString.getString());
}
@Override
public JsonString read(final JsonReader in)
throws IOException {
// TODO is there a good way to instantiate a JsonString instance?
return (JsonString) Json.createArrayBuilder()
.add(in.nextString())
.build()
.get(0);
}
}
private static final class JsonObjectTypeAdapter
extends TypeAdapter<JsonObject> {
private static final TypeAdapter<JsonObject> instance = new JsonObjectTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonObject jsonObject)
throws IOException {
out.beginObject();
for ( final Entry<String, JsonValue> e : jsonObject.entrySet() ) {
out.name(e.getKey());
jsonValueTypeAdapter.write(out, e.getValue());
}
out.endObject();
}
@Override
public JsonObject read(final JsonReader in)
throws IOException {
final JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
in.beginObject();
while ( in.hasNext() ) {
final String key = in.nextName();
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
jsonObjectBuilder.add(key, jsonValueTypeAdapter.read(in));
break;
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
jsonObjectBuilder.add(key, jsonValueTypeAdapter.read(in));
break;
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
jsonObjectBuilder.add(key, in.nextString());
break;
case NUMBER:
jsonObjectBuilder.add(key, in.nextDouble());
break;
case BOOLEAN:
jsonObjectBuilder.add(key, in.nextBoolean());
break;
case NULL:
in.nextNull();
jsonObjectBuilder.addNull(key);
break;
case END_DOCUMENT:
// do nothing
break;
default:
throw new AssertionError(token);
}
}
in.endObject();
return jsonObjectBuilder.build();
}
}
private static final class JsonArrayTypeAdapter
extends TypeAdapter<JsonArray> {
private static final TypeAdapter<JsonArray> instance = new JsonArrayTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonArray jsonArray)
throws IOException {
out.beginArray();
for ( final JsonValue jsonValue : jsonArray ) {
jsonValueTypeAdapter.write(out, jsonValue);
}
out.endArray();
}
@Override
public JsonArray read(final JsonReader in)
throws IOException {
final JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder();
in.beginArray();
while ( in.hasNext() ) {
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
jsonArrayBuilder.add(jsonValueTypeAdapter.read(in));
break;
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
jsonArrayBuilder.add(jsonValueTypeAdapter.read(in));
break;
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
jsonArrayBuilder.add(in.nextString());
break;
case NUMBER:
jsonArrayBuilder.add(in.nextDouble());
break;
case BOOLEAN:
jsonArrayBuilder.add(in.nextBoolean());
break;
case NULL:
in.nextNull();
jsonArrayBuilder.addNull();
break;
case END_DOCUMENT:
// do nothing
break;
default:
throw new AssertionError(token);
}
}
in.endArray();
return jsonArrayBuilder.build();
}
}
}
上面的代码本身就是文档,尽管它相对较大。使用示例:
private static final Gson gson = new GsonBuilder()
.serializeNulls()
.registerTypeHierarchyAdapter(JsonValue.class, getJsonValueTypeAdapter())
.create();
public static void main(final String... args) {
final JsonValue before = createObjectBuilder()
.add("boolean", true)
.add("integer", 3)
.add("string", "foo")
.addNull("null")
.add("array", createArrayBuilder()
.add(false)
.add(2)
.add("bar")
.addNull()
.build())
.build();
System.out.println("before.toString() = " + before);
final String json = gson.toJson(before);
System.out.println("type adapter result = " + json);
final JsonValue after = gson.fromJson(json, JsonValue.class);
System.out.println("after.toString() = " + after);
}
输出:
before.toString() = {"boolean":true,"integer":3,"string":"foo","null":null,"array":[false,2,"bar",null]}
type adapter result = {"boolean":true,"integer":3,"string":"foo","null":null,"array":[false,2,"bar",null]}
after.toString() = {"boolean":true,"integer":3.0,"string":"foo","null":null,"array":[false,2.0,"bar",null]}
请注意,integer
属性 值已更改:3
现在是 3.0
。发生这种情况是因为 JSON 不区分整数、长整数、浮点数、双精度数等:它只能处理一个数字。您无法真正恢复原始数字:例如,3
可能既是 long
又是 double
。您在这里最多可以做的就是不使用 .nextDouble()
而使用 .nextString()
并尝试检测它最适合哪种数字类型并分别构造一个 JsonNumber
实例(我想知道如何它可以在 javax.json
中完成——请参阅类型适配器中的 TODO 注释。
我正在尝试为 java.javax.JsonObject
s 写一个通用的 Gson serializer/deserializer:
public static class JavaxJsonObjConverter implements JsonSerializer<JsonObject>, JsonDeserializer<JsonObject> {
@Override
public JsonObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return JsonUtils.getJsonObjectFromString(json.toString());
}
@Override
public JsonElement serialize(JsonObject src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonParser().parse(src.toString());
}
}
当我尝试序列化 java.json.JsonObject
时,出现此错误:
Exception in thread "main" java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to javax.json.JsonObject
at om.headlandstech.utils.gson_utils.GsonUtils$JavaxJsonValueConverter.serialize(>GsonUtils.java:1)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapte>rFactory.java:208)
at ....
如果您也 post javax.json.JsonObject
实例(它们的构建方式),那就更好了。因为:最接近我可以重现它的是以下内容:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(JsonObject.class, new JavaxJsonObjConverter())
.create();
final JsonObject src = Json.createObjectBuilder()
.add("foo", "bar")
.build();
System.out.println(gson.toJson(src.get("foo"), JsonObject.class));
异常:
Exception in thread "main" java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to javax.json.JsonObject
at q43376802.Q43376802$JavaxJsonObjConverter.serialize(Q43376802.java:29)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.Gson.toJson(Gson.java:669)
at com.google.gson.Gson.toJson(Gson.java:648)
at com.google.gson.Gson.toJson(Gson.java:603)
at q43376802.Q43376802.main(Q43376802.java:26)
接下来。您的 JavaxJsonObjConverter
实现了 javax.json.JavaObject
(反)序列化器,但 javax.json.JavaObject
不是 javax.json
中 JSON 对象的根。层次结构根是 JsonValue
。所以你的(反)序列化器必须处理 JsonValue
而不是 JsonObject
。
public static class JavaxJsonValConverter
implements JsonSerializer<JsonValue> {
@Override
public JsonElement serialize(final JsonValue jsonValue, final Type type, final JsonSerializationContext context) {
return new JsonParser().parse(jsonValue.toString());
}
}
并通过删除和完全删除 JavaxJsonObjConverter
来注册它:
.registerTypeAdapter(JsonValue.class, new JavaxJsonValConverter())
然而,上面的序列化器是天真的,需要更多的资源,但是,给你一些灵活性(当 reading/writing 直接 from/to JSON 流可能太不合理(比较 DOM 和 XML 中的 SAX -- 这是同一个故事)):
JsonSerializer
和JsonDeserializer
依赖 JSON 用JsonElement
实现的树模型表示。这意味着必须将 entire JSON 加载到内存中,并且必须先构建其树模型,然后才能使用它。如果您要处理的 JSON 个对象很大,这将消耗更多内存。toString()
也是一个糟糕的选择:它需要先生成内部字符串,从而再次消耗内存。
所以,上面的项目可能会非常大 内存打印。为了节省内存资源,您可以创建一个可以与 JSON 流一起工作的 Gson TypeAdapter
(这是 JSON 中每个(反)序列化器的基础)。
final class JsonValueTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> jsonValueTypeAdapter = new JsonValueTypeAdapter();
private JsonValueTypeAdapter() {
}
static TypeAdapter<JsonValue> getJsonValueTypeAdapter() {
return jsonValueTypeAdapter;
}
@Override
public void write(final JsonWriter out, final JsonValue jsonValue)
throws IOException {
final ValueType valueType = jsonValue.getValueType();
switch ( valueType ) {
case ARRAY:
JsonArrayTypeAdapter.instance.write(out, (JsonArray) jsonValue);
break;
case OBJECT:
JsonObjectTypeAdapter.instance.write(out, (JsonObject) jsonValue);
break;
case STRING:
JsonStringTypeAdapter.instance.write(out, (JsonString) jsonValue);
break;
case NUMBER:
JsonNumberTypeAdapter.instance.write(out, (JsonNumber) jsonValue);
break;
case TRUE:
JsonBooleanTypeAdapter.instance.write(out, jsonValue);
break;
case FALSE:
JsonBooleanTypeAdapter.instance.write(out, jsonValue);
break;
case NULL:
JsonNullTypeAdapter.instance.write(out, jsonValue);
break;
default:
throw new AssertionError(valueType);
}
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
final JsonToken jsonToken = in.peek();
switch ( jsonToken ) {
case BEGIN_ARRAY:
return JsonArrayTypeAdapter.instance.read(in);
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
return JsonObjectTypeAdapter.instance.read(in);
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
return JsonStringTypeAdapter.instance.read(in);
case NUMBER:
return JsonNumberTypeAdapter.instance.read(in);
case BOOLEAN:
return JsonBooleanTypeAdapter.instance.read(in);
case NULL:
return JsonNullTypeAdapter.instance.read(in);
case END_DOCUMENT:
throw new AssertionError("Must never happen");
default:
throw new AssertionError(jsonToken);
}
}
private static final class JsonNullTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> instance = new JsonNullTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonValue jsonNull)
throws IOException {
out.nullValue();
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
in.nextNull();
return JsonValue.NULL;
}
}
private static final class JsonBooleanTypeAdapter
extends TypeAdapter<JsonValue> {
private static final TypeAdapter<JsonValue> instance = new JsonBooleanTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonValue jsonBoolean)
throws IllegalArgumentException, IOException {
final ValueType valueType = jsonBoolean.getValueType();
switch ( valueType ) {
case TRUE:
out.value(true);
break;
case FALSE:
out.value(false);
break;
case ARRAY:
case OBJECT:
case STRING:
case NUMBER:
case NULL:
throw new IllegalArgumentException("Not a boolean: " + valueType);
default:
throw new AssertionError(jsonBoolean.getValueType());
}
}
@Override
public JsonValue read(final JsonReader in)
throws IOException {
return in.nextBoolean() ? JsonValue.TRUE : JsonValue.FALSE;
}
}
private static final class JsonNumberTypeAdapter
extends TypeAdapter<JsonNumber> {
private static final TypeAdapter<JsonNumber> instance = new JsonNumberTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonNumber jsonNumber)
throws IOException {
if ( jsonNumber.isIntegral() ) {
out.value(jsonNumber.longValue());
} else {
out.value(jsonNumber.doubleValue());
}
}
@Override
public JsonNumber read(final JsonReader in)
throws IOException {
// TODO is there a good way to instantiate a JsonNumber instance?
return (JsonNumber) Json.createArrayBuilder()
.add(in.nextDouble())
.build()
.get(0);
}
}
private static final class JsonStringTypeAdapter
extends TypeAdapter<JsonString> {
private static final TypeAdapter<JsonString> instance = new JsonStringTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonString jsonString)
throws IOException {
out.value(jsonString.getString());
}
@Override
public JsonString read(final JsonReader in)
throws IOException {
// TODO is there a good way to instantiate a JsonString instance?
return (JsonString) Json.createArrayBuilder()
.add(in.nextString())
.build()
.get(0);
}
}
private static final class JsonObjectTypeAdapter
extends TypeAdapter<JsonObject> {
private static final TypeAdapter<JsonObject> instance = new JsonObjectTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonObject jsonObject)
throws IOException {
out.beginObject();
for ( final Entry<String, JsonValue> e : jsonObject.entrySet() ) {
out.name(e.getKey());
jsonValueTypeAdapter.write(out, e.getValue());
}
out.endObject();
}
@Override
public JsonObject read(final JsonReader in)
throws IOException {
final JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
in.beginObject();
while ( in.hasNext() ) {
final String key = in.nextName();
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
jsonObjectBuilder.add(key, jsonValueTypeAdapter.read(in));
break;
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
jsonObjectBuilder.add(key, jsonValueTypeAdapter.read(in));
break;
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
jsonObjectBuilder.add(key, in.nextString());
break;
case NUMBER:
jsonObjectBuilder.add(key, in.nextDouble());
break;
case BOOLEAN:
jsonObjectBuilder.add(key, in.nextBoolean());
break;
case NULL:
in.nextNull();
jsonObjectBuilder.addNull(key);
break;
case END_DOCUMENT:
// do nothing
break;
default:
throw new AssertionError(token);
}
}
in.endObject();
return jsonObjectBuilder.build();
}
}
private static final class JsonArrayTypeAdapter
extends TypeAdapter<JsonArray> {
private static final TypeAdapter<JsonArray> instance = new JsonArrayTypeAdapter().nullSafe();
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final JsonArray jsonArray)
throws IOException {
out.beginArray();
for ( final JsonValue jsonValue : jsonArray ) {
jsonValueTypeAdapter.write(out, jsonValue);
}
out.endArray();
}
@Override
public JsonArray read(final JsonReader in)
throws IOException {
final JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder();
in.beginArray();
while ( in.hasNext() ) {
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
jsonArrayBuilder.add(jsonValueTypeAdapter.read(in));
break;
case END_ARRAY:
throw new AssertionError("Must never happen due to delegation to the array type adapter");
case BEGIN_OBJECT:
jsonArrayBuilder.add(jsonValueTypeAdapter.read(in));
break;
case END_OBJECT:
throw new AssertionError("Must never happen due to delegation to the object type adapter");
case NAME:
throw new AssertionError("Must never happen");
case STRING:
jsonArrayBuilder.add(in.nextString());
break;
case NUMBER:
jsonArrayBuilder.add(in.nextDouble());
break;
case BOOLEAN:
jsonArrayBuilder.add(in.nextBoolean());
break;
case NULL:
in.nextNull();
jsonArrayBuilder.addNull();
break;
case END_DOCUMENT:
// do nothing
break;
default:
throw new AssertionError(token);
}
}
in.endArray();
return jsonArrayBuilder.build();
}
}
}
上面的代码本身就是文档,尽管它相对较大。使用示例:
private static final Gson gson = new GsonBuilder()
.serializeNulls()
.registerTypeHierarchyAdapter(JsonValue.class, getJsonValueTypeAdapter())
.create();
public static void main(final String... args) {
final JsonValue before = createObjectBuilder()
.add("boolean", true)
.add("integer", 3)
.add("string", "foo")
.addNull("null")
.add("array", createArrayBuilder()
.add(false)
.add(2)
.add("bar")
.addNull()
.build())
.build();
System.out.println("before.toString() = " + before);
final String json = gson.toJson(before);
System.out.println("type adapter result = " + json);
final JsonValue after = gson.fromJson(json, JsonValue.class);
System.out.println("after.toString() = " + after);
}
输出:
before.toString() = {"boolean":true,"integer":3,"string":"foo","null":null,"array":[false,2,"bar",null]}
type adapter result = {"boolean":true,"integer":3,"string":"foo","null":null,"array":[false,2,"bar",null]}
after.toString() = {"boolean":true,"integer":3.0,"string":"foo","null":null,"array":[false,2.0,"bar",null]}
请注意,integer
属性 值已更改:3
现在是 3.0
。发生这种情况是因为 JSON 不区分整数、长整数、浮点数、双精度数等:它只能处理一个数字。您无法真正恢复原始数字:例如,3
可能既是 long
又是 double
。您在这里最多可以做的就是不使用 .nextDouble()
而使用 .nextString()
并尝试检测它最适合哪种数字类型并分别构造一个 JsonNumber
实例(我想知道如何它可以在 javax.json
中完成——请参阅类型适配器中的 TODO 注释。