我正在尝试为java.javax.JsonObject编写通用的Gson序列化器/反序列化器: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 .... 最佳答案 如果同时发布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())但是,上面的序列化器很幼稚,但是需要更多资源,给您带来一些灵活性(当直接从JSON流中读取/写入JSON太不合理时(比较XML中的DOM和SAX –是同一回事)):JsonSerializer和JsonDeserializer依赖于用JsonElement实现的JSON树模型表示。这意味着必须将整个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实例(我想知道如何在-请参阅类型适配器中的TODO注释)。
07-26 01:05