我有一个类层次结构,如下所示:
interface MyEntity {
...
}
class MyEntityRef {
String id;
...
}
class MyEntityImpl {
String id;
String name;
...
}
我想将MyEntityRef
的实例序列化为纯字符串:
"someEntityId"
和MyEntityImpl
的实例作为常规对象:
{
id: "someEntityId",
name: "someName"
}
然后反过来说:当反序列化MyEntity
时,如果json是普通字符串,我希望将其反序列化为MyEntityRef
,并转换为MyEntityImpl
如果它是一个普通的json对象。
在我的实际代码中,我有许多类型的实体(即多个X
/ XRef
/ XImpl
三元组)。为了避免列出所有这些,我按如下方式对接口进行了注释:
@MyEntityAnnotation(ref=MyEntityRef.class, impl=MyEntityImpl.class)
interface MyEntity {
...
}
根据此注释信息为任何人找出解决上述序列化/反序列化的方法的额外要点。
我尝试过的事情:我能想到的一切(SimpleDeserializers
/ SimpleSerializers
,BeanDeserializerModifier
/ BeanSerializerModifier
,TypeSerializer
/ {{1 }})
答案 0 :(得分:2)
这在技术上可以通过使用自定义反序列化器(见下文),但似乎相当复杂,有点笨重,使用反射和类型不安全的转换。使用the bi-directional references可能会获得更好的运气,但这可能需要更改模型。
以下是基于自定义反序列化程序的示例:
public class JacksonEntity {
@Retention(RetentionPolicy.RUNTIME)
static public @interface MyAnnotation {
Class<?> ref();
Class<?> impl();
}
@MyAnnotation(ref = MyEntityRef.class, impl = MyEntityImpl.class)
static public interface MyEntity {
}
static public class MyEntityRef implements MyEntity {
private final String id;
public MyEntityRef(String id) {
this.id = id;
}
@JsonValue
public String getId() {
return id;
}
@Override
public String toString() {
return "MyEntityRef{" +
"id='" + id + '\'' +
'}';
}
}
static public class MyEntityImpl implements MyEntity {
public final String id;
public final String name;
@JsonCreator
public MyEntityImpl(@JsonProperty("id") String id, @JsonProperty("name") String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "MyEntityImpl{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
static public class MyDeserializer extends JsonDeserializer<Object> {
private final Class<?> refType;
private final Class<?> implType;
public MyDeserializer(MyAnnotation annotation) {
this.refType = annotation.ref();
this.implType = annotation.impl();
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonToken jsonToken = jp.getCurrentToken();
if (jsonToken == JsonToken.START_OBJECT) {
return jp.readValueAs(implType);
} else if (jsonToken == JsonToken.VALUE_STRING) {
try {
return refType.getConstructor(String.class).newInstance(jp.getValueAsString());
} catch (Exception e) {
throw new UnsupportedOperationException();
}
}
return null;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
MyAnnotation myAnnotation = beanDesc.getClassAnnotations().get(MyAnnotation.class);
// it must be interface, otherwise getting meeting recursion
if (myAnnotation != null && beanDesc.getBeanClass().isInterface()) {
return new MyDeserializer(myAnnotation);
}
return super.modifyDeserializer(config, beanDesc, deserializer);
}
});
mapper.registerModule(module);
MyEntityRef ref = new MyEntityRef("id1");
MyEntityImpl impl = new MyEntityImpl("id2", "value");
String jsonRef = mapper.writeValueAsString(ref);
System.out.println(jsonRef);
String jsonImpl = mapper.writeValueAsString(impl);
System.out.println(jsonImpl);
System.out.println(mapper.readValue(jsonRef, MyEntity.class));
System.out.println(mapper.readValue(jsonImpl, MyEntity.class));
}
}
输出:
"id1"
{"id":"id2","name":"value"}
MyEntityRef{id='id1'}
MyEntityImpl{id='id2', name='value'}