我是如何解决这个问题的。下面是一个例子项目的类图: ![class diagram](https://i.stack.imgur.com/l1OdH.png)
所以我想反序列化后得到ConcreteAAdapter
形式ConcreteA
。
我的解决方案是扩展ClassNameIdResolver
以添加将基类对象反序列化为子类类对象(子类类不增加额外的功能和附加字段)的功能。
这里是一个反序列化创建ObjectMapper
代码:
protected ObjectMapper getObjectMapperForDeserialization() {
ObjectMapper mapper = new ObjectMapper();
StdTypeResolverBuilder typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typeResolverBuilder = typeResolverBuilder.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolverBuilder.init(JsonTypeInfo.Id.CLASS, new ClassNameIdResolver(SimpleType.construct(Base.class), TypeFactory.defaultInstance()) {
private HashMap<Class, Class> classes = new HashMap<Class, Class>() {
{
put(ConcreteA.class, ConcreteAAdapter.class);
put(ConcreteB.class, ConcreteBAdapter.class);
put(ConcreteC.class, ConcreteCAdapter.class);
}
};
@Override
public String idFromValue(Object value) {
return (classes.containsKey(value.getClass())) ? value.getClass().getName() : null;
}
@Override
public JavaType typeFromId(String id) {
try {
return classes.get(Class.forName(id)) == null ? super.typeFromId(id) : _typeFactory.constructSpecializedType(_baseType, classes.get(Class.forName(id)));
} catch (ClassNotFoundException e) {
// todo catch the e
}
return super.typeFromId(id);
}
});
mapper.setDefaultTyping(typeResolverBuilder);
return mapper;
}
这里是序列化创建ObjectMapper
代码:
protected ObjectMapper getObjectMapperForSerialization() {
ObjectMapper mapper = new ObjectMapper();
StdTypeResolverBuilder typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typeResolverBuilder = typeResolverBuilder.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolverBuilder.init(JsonTypeInfo.Id.CLASS, new ClassNameIdResolver(SimpleType.construct(Base.class), TypeFactory.defaultInstance()));
mapper.setDefaultTyping(typeResolverBuilder);
return mapper;
}
测试代码:
public static void main(String[] args) throws IOException {
JacksonUtils JacksonUtils = new JacksonUtilsImpl();
Collection<Base> data = new LinkedBlockingQueue<Base>();
data.add(new ConcreteA());
data.add(new ConcreteB());
data.add(new ConcreteC());
String json = JacksonUtils.marshallIntoString(data);
System.out.println(json);
Collection<? extends Adapter> adapters = JacksonUtils.unmarshall(json, new TypeReference<ArrayList<Adapter>>() {});
for (Adapter adapter : adapters) {
System.out.println(adapter.getClass().getName());
}
}
全部JacksonUtils类的代码:
public class JacksonUtilsImpl implements JacksonUtils {
@Override
public byte[] marshall(Collection<Base> data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream() {
@Override
public byte[] toByteArray() {
return buf;
}
};
getObjectMapperForSerialization().writerWithType(new TypeReference<Collection<Base>>() {}).writeValue(out, data);
return out.toByteArray();
}
@Override
public String marshallIntoString(Collection<Base> data) throws IOException {
return getObjectMapperForSerialization().writeValueAsString(data);
}
protected ObjectMapper getObjectMapperForSerialization() {
ObjectMapper mapper = new ObjectMapper();
StdTypeResolverBuilder typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typeResolverBuilder = typeResolverBuilder.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolverBuilder.init(JsonTypeInfo.Id.CLASS, new ClassNameIdResolver(SimpleType.construct(Base.class), TypeFactory.defaultInstance()));
mapper.setDefaultTyping(typeResolverBuilder);
return mapper;
}
protected ObjectMapper getObjectMapperForDeserialization() {
ObjectMapper mapper = new ObjectMapper();
StdTypeResolverBuilder typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
typeResolverBuilder = typeResolverBuilder.inclusion(JsonTypeInfo.As.PROPERTY);
typeResolverBuilder.init(JsonTypeInfo.Id.CLASS, new ClassNameIdResolver(SimpleType.construct(Base.class), TypeFactory.defaultInstance()) {
private HashMap<Class, Class> classes = new HashMap<Class, Class>() {
{
put(ConcreteA.class, ConcreteAAdapter.class);
put(ConcreteB.class, ConcreteBAdapter.class);
put(ConcreteC.class, ConcreteCAdapter.class);
}
};
@Override
public String idFromValue(Object value) {
return (classes.containsKey(value.getClass())) ? value.getClass().getName() : null;
}
@Override
public JavaType typeFromId(String id) {
try {
return classes.get(Class.forName(id)) == null ? super.typeFromId(id) : _typeFactory.constructSpecializedType(_baseType, classes.get(Class.forName(id)));
} catch (ClassNotFoundException e) {
// todo catch the e
}
return super.typeFromId(id);
}
});
mapper.setDefaultTyping(typeResolverBuilder);
return mapper;
}
@Override
public Object unmarshall(byte[] json) throws IOException {
return getObjectMapperForDeserialization().readValue(json, Object.class);
}
@Override
public <T> T unmarshall(InputStream source, TypeReference<T> typeReference) throws IOException {
return getObjectMapperForDeserialization().readValue(source, typeReference);
}
@Override
public <T> T unmarshall(byte[] json, TypeReference<T> typeReference) throws IOException {
return getObjectMapperForDeserialization().readValue(json, typeReference);
}
@Override
public <T> Collection<? extends T> unmarshall(String json, Class<? extends Collection<? extends T>> klass) throws IOException {
return getObjectMapperForDeserialization().readValue(json, klass);
}
@Override
public <T> Collection<? extends T> unmarshall(String json, TypeReference typeReference) throws IOException {
return getObjectMapperForDeserialization().readValue(json, typeReference);
}
}
感谢您的快速回复!我更新了这个问题。简而言之,第一个服务对“ConcreteXAdapter”一无所知。所以问题是如果杰克逊在JSON中发现了'ConcreteX',那么如何告诉Jackson创建'ConcreteXAdapter'。 – pbespechnyi 2012-04-26 20:20:13
在这种情况下,我会建议手动传递类型(如“@type”:“ConcreteA”),然后根据属性反序列化另一端。即您需要为此实现自定义序列化程序。 – 2012-04-26 20:29:46
所以没有办法做到这一点开箱即用。好的,谢谢你的帮助! – pbespechnyi 2012-04-26 20:37:14