Jackson deserializar con deserializador personalizado causa una gran cantidad de llamadas GC y toma mucho más tiempo

Para solucionar mi problema de incompatibilidad de tipo discutido en este subproceso , creé Deserializers personalizados y los agregué a ObjectMapper . Sin embargo el rendimiento se deteriora significativamente con esto.

Con el deserializador por defecto consigo 1-2 llamadas de la colección de la basura en logcat mientras que con deserializer de encargo hay por lo menos 7-8 llamadas del GC, y por lo tanto el tiempo de proceso también es aumento perceptiblemente.

Mi deserializador:

 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; } }; } } 

Y estoy usando esto para agregar a 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; } } 

EDIT: Añadido datos adicionales

Mi JSON es de tamaño considerable pero no es enorme: lo he pegado aquí

Ahora para analizar el mismo JSON si uso este código:

  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; 

Entonces mi logcat es así

Pero si utilizo este código para el mismo 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; 

Entonces mi logcat es así

¿Qué tan grande es el objeto? El código construye básicamente un modelo del árbol (clase del árbol del dom), y eso tomará algo como 3x-5x tanto memoria como el documento original. Asumo que su entrada es un documento enorme de JSON.

Definitivamente puede escribir una versión más eficiente utilizando Streaming API. Algo como:

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

También es posible implementar esto con la vinculación de datos (como JsonDeserializer ), pero se complica un poco sólo porque se desea delegar en deserializador "predeterminado". Para ello, tendría que implementar BeanDeserializerModifier y reemplazar el deserializador estándar cuando se llama a "modifyDeserializer": su propio código puede retener la referencia al deserializador original y delegar en él, en lugar de usar el modelo de árbol intermedio.

Si no estás vinculado a jackson también puedes probar Genson http://code.google.com/p/genson/ . En su caso hay dos ventajas principales: usted no perderá en funcionamiento, él debe ser más fácil de poner en práctica. Si el evento de propiedad no comienza con una letra superior, anótelo con @JsonProperty ("Evento") (igual para las otras propiedades que comienzan con una letra superior). Con el siguiente código debe hacerse:

 Genson genson = new Genson.Builder() .withDeserializerFactory(new EventDeserializerFactory()).create(); YourRootClass[] bean = genson.deserialize(json, YourRootClass[].class); class EventDeserializerFactory implements Factory<Deserializer<Event>> { public Deserializer<Event> create(Type type, Genson genson) { return new EventDeserializer(genson.getBeanDescriptorFactory().provide(Event.class, genson)); } } class EventDeserializer implements Deserializer<Event> { private final Deserializer<Event> standardEventDeserializer; public EventDeserializer(Deserializer<Event> standardEventDeserializer) { this.standardEventDeserializer = standardEventDeserializer; } public Event deserialize(ObjectReader reader, Context ctx) throws TransformationException, IOException { if (ValueType.ARRAY == reader.getValueType()) { reader.beginArray().endArray(); return null; } return standardEventDeserializer.deserialize(reader, ctx); } } 
  • Cómo recuperar una lista específica de datos de firebase
  • ¿Cuál es la mejor manera de tratar con el objeto JSON?
  • problema POST android JSONObject a PHP
  • ¿Objeto raíz o no? ¿Cuál es la mejor práctica para las respuestas de la API?
  • Almacenamiento en caché de los datos descargados de JSON en la base de datos SQLite - ¿es una buena idea?
  • Android - Ruby on Rails - MySQL
  • Extraer el cuerpo del mensaje de HttpResponse
  • Cómo utilizar parámetros con HttpPost
  • Error de autenticación: no se puede responder a ninguno de estos desafíos: {} Android - 401 no autorizado
  • ¿Utilizar JSONArray en otra clase?
  • ¿Cómo obtener datos Instagram de un usuario en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.