杰克逊使用自定义反序列化器进行反序列化会导致大量的GC调用,并且需要更长的时间

vKa*_*yap 7 java android json jackson

为了解决我在这个线程中讨论的类型不匹配问题,我创建了自定义Deserializers并将它们添加到ObjectMapper.然而,性能随之显着恶化.

使用默认的解串器,我可以获得1-2个垃圾收集调用,logcat而使用自定义解串器时,至少有7-8个GC调用,因此处理时间也会显着增加.

我的解串器:

public class Deserializer<T> {

public JsonDeserializer<T> getDeserializer(final Class<T> cls) {
  return new JsonDeserializer<T> (){

     @Override
     public T deserialize(JsonParser jp, DeserializationContext arg1) throws IOException, JsonProcessingException {
        JsonNode node = jp.readValueAsTree();
        if (node.isObject()) {
          return new ObjectMapper().convertValue(node, cls);
        }
        return null;
     }
 };
}
} 
Run Code Online (Sandbox Code Playgroud)

我正在使用它添加到Mapper

public class DeserializerAttachedMapper<T> {

   public ObjectMapper getMapperAttachedWith(final Class<T> cls , JsonDeserializer<T> deserializer) {
      ObjectMapper mapper = new ObjectMapper();
      SimpleModule module = new SimpleModule(deserializer.toString(), new Version(1, 0, 0, null, null, null));
      module.addDeserializer(cls, deserializer);
      mapper.registerModule(module);
      return mapper;
   }
}
Run Code Online (Sandbox Code Playgroud)

编辑:添加额外数据

我的JSON尺寸相当大但不是很大:我在这里贴了

现在,如果我使用此代码解析相同的JSON:

   String response = ConnectionManager.doGet(mAuthType, url, authToken);
    FLog.d("location object response" + response);
  //        SimpleModule module = new SimpleModule("UserModule", new Version(1, 0, 0, null, null, null));
  //        JsonDeserializer<User> userDeserializer = new Deserializer<User>().getDeserializer(User.class);     
  //        module.addDeserializer(User.class, userDeserializer);

    ObjectMapper mapper = new ObjectMapper();
  //        mapper.registerModule(module);
    JsonNode tree = mapper.readTree(response);
    Integer code = Integer.parseInt(tree.get("code").asText().trim());

    if(Constants.API_RESPONSE_SUCCESS_CODE == code) {
        ExploreLocationObject locationObject = mapper.convertValue(tree.path("response").get("locationObject"), ExploreLocationObject.class);
        FLog.d("locationObject" + locationObject);
        FLog.d("locationObject events" + locationObject.getEvents().size());
        return locationObject;
    }       
    return null;    
Run Code Online (Sandbox Code Playgroud)

然后我的logcat就是这样

但是,如果我将此代码用于相同的JSON

        String response = ConnectionManager.doGet(mAuthType, url, authToken);
    FLog.d("location object response" + response);
    SimpleModule module = new SimpleModule("UserModule", new Version(1, 0, 0, null, null, null));
    JsonDeserializer<User> userDeserializer = new Deserializer<User>().getDeserializer(User.class);

    module.addDeserializer(User.class, userDeserializer);
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(module);
    JsonNode tree = mapper.readTree(response);
    Integer code = Integer.parseInt(tree.get("code").asText().trim());

    if(Constants.API_RESPONSE_SUCCESS_CODE == code) {
        ExploreLocationObject locationObject = mapper.convertValue(tree.path("response").get("locationObject"), ExploreLocationObject.class);
        FLog.d("locationObject" + locationObject);
        FLog.d("locationObject events" + locationObject.getEvents().size());
        return locationObject;
    }       
    return null;        
Run Code Online (Sandbox Code Playgroud)

然后我的logcat就是这样

Sta*_*Man 3

该物体有多大?代码基本上构建了一个树模型(类似于 dom 树),这将占用原始文档 3 到 5 倍的内存。所以我假设您的输入是一个巨大的 JSON 文档。

您绝对可以使用 Streaming API 编写更高效的版本。就像是:

JsonParser jp = mapper.getJsonFactory().createJsonParser(input);
JsonToken t = jp.nextToken();
if (t == JsonToken.START_OBJECT) {
   return mapper.readValue(jp, classToBindTo);
}
return null;
Run Code Online (Sandbox Code Playgroud)

也可以使用数据绑定(如JsonDeserializer)来实现这一点,但是仅仅因为您想委托给“默认”反序列化器,它就会变得有点复杂。为此,您需要实现BeanDeserializerModifier,并在调用“modifyDeserializer”时替换标准反序列化器:您自己的代码可以保留对原始反序列化器的引用并委托给它,而不是使用中间树模型。