我是一个可以通过许多具体类型实现的OID接口:
public interface OID {
}
public abstract class OIDBase
implements OID {
private String _id;
}
public class MyOID
extends OIDBase {
public MyOID() {
// default no-args constructor
}
}
public class MyOtherOID
extends OIDBase {
public MyOtherOID() {
// default no-args constructor
}
}
现在我有一个包含两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义
public class MyBean {
private OID _absOid;
private MyOID _concreteOid;
public MyBean(final OID absOid,final MyOID concreteOid) {
_absOid = absOid;
_concreteOid = concreteOid;
}
}
我想使用jackson以不同方式序列化/反序列化字段,无论它们是使用抽象接口类型还是使用具体类型定义的:
{
"_absOid": {
"type" : "MyOtherOID",
"id" : "__an_id__"
},
"_concreteOid" : "__another_id___"
}
请注意_absOid
已序列化,包括类型信息(多态序列化),_concreteOid
序列化为文本
为此,我将OID界面注释为:
@JsonSubTypes({
@JsonSubTypes.Type(MyOID.class),
@JsonSubTypes.Type(MyOtherOID.class)
})
public interface OID {
}
并为每个具体类型分配了一个类型ID:
@JsonTypeName("MyOID")
public class MyOID
extends OIDBase {
...
}
@JsonTypeName("MyOtherOID")
public class MyOtherOID
extends OIDBase {
...
}
最后,容器bean中的抽象定义字段被注释为使jackson包含类型信息:
public class MyBean {
@JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY,
use = JsonTypeInfo.Id.NAME,
property = "type")
private OID _absOid;
private MyOID _concreteOid;
}
到目前为止,非常好,但是如果使用抽象类型(OID)定义字段并且如果使用具体类型(MyOID)定义字段,则以不同方式序列化,我必须创建自定义序列化器:< / p>
首先注释使用序列化器/反序列化器的具体类型:
@JsonTypeName("MyOID")
@JsonSerialize(using=OIDSerializer.class) @JsonDeserialize(using=OIDDeSerializer.class)
public class MyOID
extends OIDBase {
...
}
@JsonTypeName("MyOtherOID")
@JsonSerialize(using=OIDSerializer.class) @JsonDeserialize(using=OIDDeSerializer.class)
public class MyOtherOID
extends OIDBase {
...
}
...序列化/解串器代码:
public static class OIDSerializer
extends JsonSerializer<OID> {
@Override
public void serialize(final OID value,
final JsonGenerator jgen,
final SerializerProvider provider) throws IOException,JsonProcessingException {
// **** used when serializing a concrete type
jgen.writeString(value.toString());
}
@Override
public void serializeWithType(final OID value,
final JsonGenerator jgen,
final SerializerProvider provider,
final TypeSerializer typeSer) throws IOException {
// **** used when serializing a polymorphic type
// guess the type id
WritableTypeId typeId = typeSer.typeId(value,JsonToken.START_OBJECT);
// type prefix
typeSer.writeTypePrefix(jgen,
typeId);
// object
jgen.writeFieldName("id");
jgen.writeString(value.toString());
// type suffix
typeId.wrapperWritten = !jgen.canWriteTypeId();
typeSer.writeTypeSuffix(jgen,
typeId);
}
}
问题在反序列化 json字符串时出现,我使用了以下自定义反序列化器:
public static class OIDDeSerializer
extends StdDeserializer<OID> {
public MyOIDDeSerializer() {
super(MyOID.class);
}
@Override
public OID deserialize(final JsonParser jp,
final DeserializationContext ctxt) throws IOException,JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
// [1] - Read the id depending on the serialized format
String oidStr = null;
// text node > concrete oid impl serialized as [value]
if (node.getNodeType() == JsonNodeType.STRING) {
oidStr = ((TextNode)node).asText();
}
// oid=value > abstract oid impl serialized as {typeId=[type],oid={value]}
else {
ObjectNode objNode = (ObjectNode)node;
oidStr = objNode.findValue("id").asText();
}
// [2] - Read tye type id
String typeId = objNode.findValue("type").asText()
// PROBLEM!!!!!!
// how get the type from the typeId in order to create the concrete instance
// how access the type resolver????
Class<? extends OID> oidType = RESOLVE TYPE FROM THE ID
return oidType.newInstance();
}
}
所以问题 如何在自定义反序列化 ???
中访问类型ID解析中的类型答案 0 :(得分:2)
你可以试试这个:
AnnotationIntrospector annotationInspector = new JacksonAnnotationIntrospector();
AnnotatedClass annotatedClass = AnnotatedClass.constructWithoutSuperTypes(OID.class,
new ObjectMapper().getSerializationConfig());
List<NamedType> subtypes = annotationInspector.findSubtypes(annotatedClass);
for(NamedType type: subtypes){
if(type.getType().getName().contains(typeId)){
return type.getClass().newInstance();
}
}
答案 1 :(得分:1)
序列化程序必须注意这个字段可能与类型信息一起序列化(当使用抽象类型声明字段时) ...所以序列化器必须覆盖serializeWithType()
public static class OIDSerializer
extends JsonSerializer<OID> {
@Override
public void serialize(final OID value,
final JsonGenerator jgen,
final SerializerProvider provider) throws IOException,JsonProcessingException {
jgen.writeString(value.asString());
}
@Override
public void serializeWithType(final OID value,
final JsonGenerator jgen,
final SerializerProvider provider,
final TypeSerializer typeSer) throws IOException {
// guess the type id
WritableTypeId typeId = typeSer.typeId(value,JsonToken.START_OBJECT);
// type prefix
typeSer.writeTypePrefix(jgen,
typeId);
// object
jgen.writeFieldName("idStr");
jgen.writeString(value.asString());
// type suffix
typeId.wrapperWritten = !jgen.canWriteTypeId();
typeSer.writeTypeSuffix(jgen,
typeId);
}
}
另一方面,反序列化器的有趣部分是使用@ Sachin在_oidTypeFromId()方法中的尖头解决方案从typeId解析类型的位置:
public static class OIDDeSerializer
extends StdDeserializer<OID>
implements ContextualDeserializer {
// property being deserialized
private BeanProperty _property;
public OIDDeSerializer() {
super(OID.class);
}
@Override
public JsonDeserializer<?> createContextual(final DeserializationContext ctxt,
final BeanProperty property) throws JsonMappingException {
_property = property;
return this;
}
@Override
public OID deserialize(final JsonParser parser,
final DeserializationContext ctxt) throws IOException,
JsonProcessingException {
String idStr = null; // the oid
Class<? extends OID> oidType = null; // the oid type
JsonNode node = parser.getCodec().readTree(parser);
// [1] - Read the id depending on the serialized format
// text node > concrete oid impl serialized as [value]
if (node.getNodeType() == JsonNodeType.STRING) {
idStr = ((TextNode)node).asText();
oidType = (Class<? extends OID>)_property.getType().getRawClass();
}
// oid=value > abstract oid impl serialized as {typeId=[type],oid={value]}
else {
ObjectNode objNode = (ObjectNode)node;
idStr = objNode.findValue("idStr").asText();
String typeId = objNode.findValue("typeId").asText();
oidType = (Class<? extends OID>)_oidTypeFromId(ctxt.getAnnotationIntrospector(),
ctxt.getConfig(),
typeId);
}
// [2] - Get the oid type
OID outOid = ReflectionUtils.createInstanceFromString(oidType,idStr);
return outOid;
}
private Class<? extends OID> _oidTypeFromId(final AnnotationIntrospector annotationIntrospector,
final DeserializationConfig cfg,
final String typeId) {
Class<? extends OID> outType = null;
AnnotatedClass annotatedClass = AnnotatedClassResolver.resolveWithoutSuperTypes(cfg,
OID.class);
List<NamedType> subtypes = annotationIntrospector.findSubtypes(annotatedClass);
for (NamedType type: subtypes){
if (type.getName().equals(typeId)){
outType = (Class<? extends OID>)type.getType();
}
}
return outType;
}
}