过去几天我一直在研究这个问题,尽管我觉得我已接近实现,但我不能100%确定它是否可行。
简而言之,我想要实现的目标是高级使用"多态反序列化"满足以下要求:
我们说我有以下实体,例如:
public class Request
{
public String currency;
}
public class RequestA extends Request
{
public String fieldA;
}
public class RequestB extends Request
{
public String fieldB;
}
我也有这个自定义类型ID解析器:
public class CustomTypeIdResolver extends TypeIdResolverBase
{
private JavaType superType;
@Override
public void init(JavaType baseType)
{
superType = baseType;
}
@Override
public String idFromValue(Object value)
{
return idFromValueAndType(value, value.getClass());
}
@Override
public String idFromValueAndType(Object value, Class<?> suggestedType)
{
String typeId = null;
switch (suggestedType.getSimpleName()) {
case "RequestA":
typeId = "A";
break;
case "RequestB":
typeId = "B";
}
return typeId;
}
@Override
public JavaType typeFromId(DatabindContext context, String id) {
Class<?> subType = null;
switch (id) {
case "A":
subType = RequestA.class;
break;
case "B":
subType = RequestB.class;
}
return context.constructSpecializedType(superType, subType);
}
@Override
public JsonTypeInfo.Id getMechanism()
{
return JsonTypeInfo.Id.CUSTOM;
}
}
这个自定义注释introspector:
public class CustomAnnotationIntrospector extends JacksonAnnotationIntrospector
{
@Override
public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType)
{
// Preserve default behaviour
TypeResolverBuilder<?> typeResolver = super.findTypeResolver(config, ac, baseType);
if (typeResolver != null ) {
return typeResolver;
}
if (ac.getAnnotated().equals(RequestA.class)) {
typeResolver = new StdTypeResolverBuilder();
typeResolver = typeResolver.init(JsonTypeInfo.Id.CUSTOM, new CustomTypeIdResolver());
typeResolver = typeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolver.typeProperty("@type");
} else if (ac.getAnnotated().equals(RequestB.class)) {
typeResolver = new StdTypeResolverBuilder();
typeResolver = typeResolver.init(JsonTypeInfo.Id.CUSTOM, new CustomTypeIdResolver());
typeResolver = typeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolver.typeProperty("@type");
}
return typeResolver;
}
}
当我像这样运行时:
@Test
public void test() throws Exception
{
Request r = new Request();
r.currency = "R";
RequestA a = new RequestA();
a.currency = "A";
a.fieldA = "field A";
RequestB b = new RequestB();
b.currency = "B";
b.fieldB = "field B";
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new CustomAnnotationIntrospector());
String contentR = write(mapper, r);
String contentA = write(mapper, a);
String contentB = write(mapper, b);
Request readR = read(mapper, contentR);
RequestA readA = (RequestA) read(mapper, contentA);
RequestB readB = (RequestB) read(mapper, contentB);
assertEquals(r, readR);
assertEquals(a, readA);
assertEquals(b, readB);
}
private static String write(ObjectMapper mapper, Request r) throws Exception
{
String content = mapper.writeValueAsString(r);
System.out.println(content);
return content;
}
private static Request read(ObjectMapper mapper, String value) throws Exception
{
return mapper.readValue(value, Request.class);
}
我得到了这个输出:
{"currency":"R"}
{"@type":"A","currency":"A","fieldA":"field A"}
{"@type":"B","currency":"B","fieldB":"field B"}
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "@type" (class cvo.experiments.Request), not marked as ignorable (one known property: "currency"])
at [Source: {"@type":"A","currency":"A","fieldA":"field A"}; line: 1, column: 11] (through reference chain: cvo.experiments.Request["@type"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
at cvo.experiments.MapperTest.read(MapperTest.java:200)
at cvo.experiments.MapperTest.without_annotations_best(MapperTest.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
这就是发生的事情:
我想知道我试图实现的目标是否可行。如果是的话,我的做法有什么不对?