自定义Json反序列化器用于泛型类类型

时间:2018-01-25 07:01:24

标签: json generics jackson deserialization json-deserialization

考虑一个类型为“服装”的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中删除标题(因为标头未在我的目标类类型中定义,因为反序列化将失败)

我需要编写一个返回泛型类类型对象的自定义反序列化器。它将检查是否有标头,获取目标类名,删除标头并将其反序列化为获取的目标类并返回。

这是我编写的代码,但它不起作用,我甚至不确定是否可以在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;
}

My 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();
    }
}

1 个答案:

答案 0 :(得分:0)

this.objectMapper.readValue(stringValue, clazz);  类型的&#39; clazz&#39;在这个readValue方法中应该匹配在simpleModule.addDeserializer中传递的类类型。

它不会进入您的反序列化器,因为您要将解串器添加到SimpleModule中以用于&#39;对象&#39;不同类的班级和阅读价值传递给&#39;服装反序列化&#39;,