準確地說,這是Jackson 2.2.3。Jackson 2.2.x:遞歸反序列化失敗,爲什麼?
的反序列化過程是相當複雜的,因爲這取決於JSON值I反序列化,類的變化的類型:
- 基,抽象類是
JsonMergePatch
; - 當JSON值不是JSON對象時,我反序列化爲
NonObjectMergePatch
; - 否則,我遞歸反序列化爲
ObjectMergePatch
。
下面是代碼(省略了「簡潔進口);第一,JsonMergePatch
:
@JsonDeserialize(using = JsonMergePatchDeserializer.class)
public abstract class JsonMergePatch
implements JsonSerializable
{
public abstract JsonNode apply(final JsonNode input)
throws JsonPatchException;
}
NonObjectMergePatch
:
final class NonObjectMergePatch
extends JsonMergePatch
{
private final JsonNode node;
NonObjectMergePatch(@Nonnull final JsonNode node)
{
this.node = Preconditions.checkNotNull(node);
}
@Override
public JsonNode apply(final JsonNode input)
throws JsonPatchException
{
return null; // TODO!
}
@Override
public void serialize(final JsonGenerator jgen,
final SerializerProvider provider)
throws IOException, JsonProcessingException
{
jgen.writeTree(node);
}
@Override
public void serializeWithType(final JsonGenerator jgen,
final SerializerProvider provider, final TypeSerializer typeSer)
throws IOException, JsonProcessingException
{
serialize(jgen, provider);
}
}
ObjectMergePatch
:
final class ObjectMergePatch
extends JsonMergePatch
{
private final Set<String> removedMembers;
private final Map<String, JsonMergePatch> modifiedMembers;
ObjectMergePatch(final Set<String> removedMembers,
final Map<String, JsonMergePatch> modifiedMembers)
{
this.removedMembers = ImmutableSet.copyOf(removedMembers);
this.modifiedMembers = ImmutableMap.copyOf(modifiedMembers);
}
@Override
public JsonNode apply(final JsonNode input)
throws JsonPatchException
{
return null;
}
@Override
public void serialize(final JsonGenerator jgen,
final SerializerProvider provider)
throws IOException, JsonProcessingException
{
jgen.writeStartObject();
/*
* Write removed members as JSON nulls
*/
for (final String member: removedMembers)
jgen.writeNullField(member);
/*
* Write modified members; delegate to serialization for writing values
*/
for (final Map.Entry<String, JsonMergePatch> entry:
modifiedMembers.entrySet()) {
jgen.writeFieldName(entry.getKey());
entry.getValue().serialize(jgen, provider);
}
jgen.writeEndObject();
}
@Override
public void serializeWithType(final JsonGenerator jgen,
final SerializerProvider provider, final TypeSerializer typeSer)
throws IOException, JsonProcessingException
{
serialize(jgen, provider);
}
}
最後,自定義的deserial izer:
final class JsonMergePatchDeserializer
extends JsonDeserializer<JsonMergePatch>
{
@Override
public JsonMergePatch deserialize(final JsonParser jp,
final DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
/* FAILS HERE */
final JsonNode node = jp.readValueAsTree();
/*
* Not an object: the simple case
*/
if (!node.isObject())
return new NonObjectMergePatch(node);
/*
* The complicated case...
*
* We have to build a set of removed members, plus a map of modified
* members.
*/
final Set<String> removedMembers = Sets.newHashSet();
final Map<String, JsonMergePatch> modifiedMembers = Maps.newHashMap();
final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
Map.Entry<String, JsonNode> entry;
while (iterator.hasNext()) {
entry = iterator.next();
if (entry.getValue().isNull())
removedMembers.add(entry.getKey());
else {
final JsonMergePatch value
= deserialize(entry.getValue().traverse(), ctxt);
modifiedMembers.put(entry.getKey(), value);
}
}
return new ObjectMergePatch(removedMembers, modifiedMembers);
}
/*
* This method MUST be overriden... The default is to return null, which is
* not what we want.
*/
@Override
public JsonMergePatch getNullValue()
{
return new NonObjectMergePatch(NullNode.getInstance());
}
}
我已編碼的測試工作正常,只要反序列化的JSON不是一個對象;當它是一個對象,我遞歸調用的方法deserialize()
反序列化對象的成員值......但閱讀從解析器值失敗與此異常(上面注/* FAILS HERE */
):
java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree
at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1352)
at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:67)
at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:92)
at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:36)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
at com.github.fge.jsonpatch.rfc7386.SerializationTest.objectSerDeserWorksCorrectly(SerializationTest.java:102)
爲什麼?我怎麼解決這個問題?
這應該沒有必要,因爲它會很醜。數據綁定代碼應該在需要爲緩衝令牌創建臨時解析器的情況下傳播'codec'實例;所以這聽起來像是一個錯誤的地方。相反,如果自定義反序列化器使用緩衝,則需要確保爲'TokenBuffer'傳遞'JsonParser'。 – StaxMan 2014-10-31 17:22:52
嗯,所以我用2.2.3;我還沒有使用2.2.4,這會有所作爲嗎? – fge 2014-10-31 17:30:52
啊。很可能 - 從那時起,類似的問題就得到解決。雖然我會嘗試使用高達2.4.3,如果可能和必要(即如果問題仍然存在,請嘗試查看後續版本是否修復)。 2.4.3有我能想到的所有相關修復。 – StaxMan 2014-10-31 17:34:43