【发布时间】:2018-01-25 07:01:24
【问题描述】:
考虑一个“服装”类型的 json:
{
"id":"123",
"version":2,
"apparel":{
"category":[
{
"id":"a1",
"style":"top",
"comments":[
{
"header":{
"type":"apparel.detail.Summary",
"major_version":1,
"minor_version":0
},
"summary": "notes"
}]
}
]
},
"accessories":[
{
"header":{
"type":"accessories.detail.Handbag",
"major_version":1,
"minor_version":0
},
"details":{
"brand":"Gucci",
"sno.":"G12"
},
"color":"Red",
},
{
"header":{
"type":"accessories.detail.Hat",
"major_version":1,
"minor_version":0
},
"details":{
"brand":"Adidas",
"sno.":"A12"
}
}
]
}
我无法访问“服装”,我无法添加任何字段级别或类级别的 json 注释。 json 中有一个属性“header”可以帮助我确定我想要将该实体转换为的类的类型。一旦确定了类类型,我将从我的 json 中删除标头(因为标头未在我的目标类类型中定义,因为反序列化将失败)
我需要编写一个返回通用类类型对象的自定义反序列化器。它将检查是否有header,获取目标类名,删除header并将其反序列化为获取的目标类并返回。
这是我编写的代码,但它不起作用,我什至不确定是否可以在 SimpleModule 中注入具有通用返回类型的自定义反序列化器。
@Singleton
@Provides
private Transformer provideTransformer(final HeaderDeserializer headerDeserializer) {
final SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(Object.class, headerDeserializer);
mapper.registerModule(simpleModule);
}
@Singleton
@Provides
private HeaderDeserializer provideHeaderDeserializer(final ObjectMapper objectMapper) {
return new HeaderDeserializer(objectMapper);
}
@Singleton
@Provides
private ObjectMapper provideObjectMapper() {
final ObjectMapper mapper = new ObjectMapper()
// Tell object mapper how to handle joda-time.
.registerModule(new JodaModule())
// include non-null values only
.setSerializationInclusion(Include.NON_NULL)
// ensures that timezone is preserved
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
return mapper;
}
我的 HeaderDeserializer 看起来像这样:
public class HeaderDeserializer<T> extends StdDeserializer<T> {
private static final long serialVersionUID = 1L;
private final ObjectMapper mapper;
public HeaderDeserializer(final ObjectMapper mapper) {
this(null, mapper);
}
public HeaderDeserializer(final Class<?> vc, final ObjectMapper mapper) {
super(vc);
this.mapper = mapper;
}
@Override
public T deserialize(final JsonParser jp, final DeserializationContext ctx) {
Object value = null;
try {
JsonNode node = this.mapper.readTree(jp);
JsonNode header = node.get("header");
if (node.has("header")) {
String targetClass = header.get("type").textValue();
removeHeaderFromJsonDoc(node);
value = this.mapper.readValue(jp, Class.forName(targetClass));
}
} catch (final IOException e) {
throw new UncheckedIOException(e);
} catch (final ClassNotFoundException e) {
// do somehting
}
return (T) value;
}
private void removeHeaderFromJsonDoc(final JsonNode document) {
final Iterator<Entry<String, JsonNode>> itr = document.fields();
while (itr.hasNext()) {
final Entry<String, JsonNode> childNodeEntry = itr.next();
if (childNodeEntry.getKey().equals("header")) {
itr.remove();
}
}
}
}
我的主要反序列化器将使用上面定义的自定义反序列化器,如下所示:
public final Clothing deserialize(
final String stringValue,
final Class<? extends Clothing> clazz) {
try {
return this.objectMapper.readValue(stringValue, clazz);
} catch (final IOException e) {
throw new IllegalArgumentException();
}
}
【问题讨论】:
-
什么“不起作用”?你有例外吗?对象类型错误?
-
HeaderDeserializer是用泛型定义的,但被实例化为原始类型并关联到Object.class,那么为什么用泛型定义它呢?让它返回Object -
反序列化时不调用HeaderDeserializer的deserialize方法。我也尝试了你的建议,但都没有进入反序列化方法。
标签: json generics jackson deserialization json-deserialization