问题描述
现在我正在与杰克逊(Jackson)合作,对此我有一些疑问.
Now i'm working with Jackson and i have some questions about it.
首先.我有两项服务,第一项是数据收集和发送服务,第二项是接收此数据,例如将其记录到文件中.
First of all. I have two services, first is data collecting and sending service and second receive this data and, for example, log it into a file.
因此,第一个服务具有这样的类层次结构:
So, first service has class hierarchy like this:
+----ConcreteC
|
Base ----+----ConcreteA
|
+----ConcreteB
第二个服务具有这样的类层次结构:
And second service has class hierarchy like this:
ConcreteAAdapter extends ConcreteA implements Adapter {}
ConcreteBAdapter extends ConcreteB implements Adapter {}
ConcreteCAdapter extends ConcreteC implements Adapter {}
第一个服务对ConcreteXAdapter
一无所知.
The first service knows nothing about ConcreteXAdapter
.
我在第一个服务上发送数据的方式:
The way i'm sending the data on the first service:
Collection<Base> data = new LinkedBlockingQueue<Base>()
JacksonUtils utils = new JacksonUtils();
data.add(new ConcreteA());
data.add(new ConcreteB());
data.add(new ConcreteC());
...
send(utils.marshall(data));
...
public class JacksonUtils {
public byte[] marshall(Collection<Base> data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream() {
@Override
public byte[] toByteArray() {
return buf;
}
};
getObjectMapper().writeValue(out, data);
return out.toByteArray();
}
protected ObjectMapper getObjectMapper() {
return new ObjectMapper();
}
public Object unmarshall(byte[] json) throws IOException {
return getObjectMapper().readValue(json, Object.class);
}
public <T> T unmarshall(InputStream source, TypeReference<T> typeReference) throws IOException {
return getObjectMapper().readValue(source, typeReference);
}
public <T> T unmarshall(byte[] json, TypeReference<T> typeReference) throws IOException {
return getObjectMapper().readValue(json, typeReference);
}
}
因此,我想将json反序列化为ConcreteXAdapter
的集合,而不是ConcreteX
(ConcreteA -> ConcreteAAdapter, ConcreteB -> ConcreteBAdapter, ConcreteC -> ConcreteCAdapter
)的集合.在我描述的情况下,我想获得:
So, i want to desirialize json into Collection of ConcreteXAdapter
, not into Collection of ConcreteX
(ConcreteA -> ConcreteAAdapter, ConcreteB -> ConcreteBAdapter, ConcreteC -> ConcreteCAdapter
). In the case i described i want to get:
Collection [ConcreteAAdapter, ConcreteBAdapter, ConcreteCAdapter]
我该怎么做?
推荐答案
我如何解决此问题.这是示例项目的类图:
How I solved this problem. Here is a class diagram for an example project:
所以我想在反序列化后得到ConcreteAAdapter
形式的ConcreteA
.
So i want to get the ConcreteAAdapter
form ConcreteA
after deserialization.
我的解决方案是扩展ClassNameIdResolver
以添加将基类对象反序列化为子类型类对象的功能(子类型类不添加任何附加功能和附加字段).
My solution is to extend ClassNameIdResolver
to add functionality to deserialize base class objects into subtype class objects (subtype classes adds no extra functionality and additional fields).
以下是创建用于反序列化的ObjectMapper
的代码:
Here is a code which creates ObjectMapper
for deserialization:
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
进行序列化的代码:
And here is a code which create ObjectMapper
for serialization:
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类的完整代码:
Full code of JacksonUtils class:
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);
}
}
这篇关于使用Jackson将Json反序列化为其他类层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!