【发布时间】:2012-11-01 10:46:28
【问题描述】:
为了解决我在in this thread 讨论的类型不匹配问题,我创建了自定义Deserializers 并将它们添加到ObjectMapper。但是,性能会因此而显着下降。
使用默认反序列化器,我在logcat 中获得 1-2 次垃圾收集调用,而使用自定义反序列化器至少有 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;
}
};
}
}
我正在使用它来添加到 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;
}
}
编辑:添加额外数据
我的 JSON 相当大,但不是很大: 我已经粘贴了it here
如果我使用此代码,现在解析相同的 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;
那我的logcat是like this
但如果我将此代码用于相同的 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;
那我的logcat是like this
【问题讨论】:
-
补充一点:确保你重用了
ObjectMapper——它是一个重量级的对象,不应该在每个请求中创建一次。否则它肯定会导致大量的 GC 活动。仅从上面的代码很难确定。 -
实际上我注意到您的反序列化器创建了一个 ObjectMapper:这是非常昂贵的。您可以通过使用
JsonParser.getCodec()来避免这种情况,将结果转换为ObjectMapper(这是安全的向上转换)。这也应该有很大帮助。 -
我修改了我的代码并将对象映射器添加到我的单例中,默认反序列化器的性能有所提高,但自定义反序列化器的问题仍然存在。另外,我注意到如果我将两个反序列化器添加到同一个模块,那么默认的反序列化器会被调用,而不是自定义的反序列化器。
JsonParser.getCodec()不是静态方法,所以我必须为每个请求创建JsonParser。不会也很贵吧?? -
两个反序列化器的行为听起来不对;只有在没有自定义类型的情况下才应调用默认值。在
JsonParser-- 不应该创建新的,但如果你在deserialize(...)方法中,你会被传递一个(不是映射器)。所以我要说的是,如果你有JsonParser或JsonGenerator(有引用;如果解析器/生成器是由ObjectMapper创建的,则为真),你总能找到一个映射器。 -
只是想在反序列化器中添加
Jsonparser.getCodec()在这种情况下导致stackOverFlow异常,可能是因为它调用了与反序列化器相同的deserialize(JsonParser jp, DeserializationContext arg1)方法,导致无限循环。