私はカスタムジャクソンデシリアライザーを書こうとしています。 1つのフィールドを「見て」、クラスへの自動逆シリアル化を実行したいのですが、以下の例を参照してください。
_import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.mypackage.MyInterface;
import com.mypackage.MyFailure;
import com.mypackage.MySuccess;
import Java.io.IOException;
public class MyDeserializer extends JsonDeserializer<MyInterface> {
@Override
public MyInterface deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectCodec codec = jp.getCodec();
JsonNode node = codec.readTree(jp);
if (node.has("custom_field")) {
return codec.treeToValue(node, MyFailure.class);
} else {
return codec.treeToValue(node, MySuccess.class);
}
}
}
_
ポジョス:
_public class MyFailure implements MyInterface {}
public class MySuccess implements MyInterface {}
@JsonDeserialize(using = MyDeserializer.class)
public interface MyInterface {}
_
そして、私はStackOverflowError
を手に入れました。 _codec.treeToValue
_が同じデシリアライザーを呼び出すことを理解してください。カスタム脱セラライザー内で_codec.treeToValue
_またはObjectMapper.readValue(String,Class<T>)
を使用する方法はありますか?
差し迫った問題は、MyInterfaceの実装とMyInterface自体のために@JsonDeserialize(using=...)
が取得されていること、つまり無限のループであるようです。
これを修正して、各実装の設定を上書きすることができます。
@JsonDeserialize(using=JsonDeserializer.None.class)
public static class MySuccess implements MyInterface {
}
または、アノテーションの代わりにモジュールを使用して逆シリアル化を構成する(およびMyInterfaceからアノテーションを削除する):
mapper.registerModule(new SimpleModule() {{
addDeserializer(MyInterface.class, new MyDeserializer());
}});
ちなみに、JsonNodeに基づく逆シリアル化を実装するためにStdNodeBasedDeserializer
を拡張することも検討してください。例えば:
@Override
public MyInterface convert(JsonNode root, DeserializationContext ctxt) throws IOException {
Java.lang.reflect.Type targetType;
if (root.has("custom_field")) {
targetType = MyFailure.class;
} else {
targetType = MySuccess.class;
}
JavaType jacksonType = ctxt.getTypeFactory().constructType(targetType);
JsonDeserializer<?> deserializer = ctxt.findRootValueDeserializer(jacksonType);
JsonParser nodeParser = root.traverse(ctxt.getParser().getCodec());
nodeParser.nextToken();
return (MyInterface) deserializer.deserialize(nodeParser, ctxt);
}
このカスタムデシリアライザーには、特にデシリアライズのコンテキストの追跡などに関して、多くの改善が加えられていますが、これにより、必要な機能が提供されるはずです。
これは私にとってトリックでした:
ctxt.readValue(node, MyFailure.class)
カスタムデシリアライザー内で独自のObjectMapper
を使用するには、 Jackson Mix-in Annotations (theDefaultJsonDeserializer
interface)POJO
クラスからカスタムデシリアライザーを動的に削除し、StackOverflowError
objectMapper.readValue(JsonParser, Class<T>)
の結果としてスローされます。
public class MyDeserializer extends JsonDeserializer<MyInterface> {
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.addMixIn(MySuccess.class, DefaultJsonDeserializer.class);
objectMapper.addMixIn(MyFailure.class, DefaultJsonDeserializer.class);
}
@Override
public MyInterface deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
if (jp.getCodec().<JsonNode>readTree(jp).has("custom_field")) {
return objectMapper.readValue(jp, MyFailure.class);
} else {
return objectMapper.readValue(jp, MySuccess.class);
}
}
@JsonDeserialize
private interface DefaultJsonDeserializer {
// Reset default json deserializer
}
}