/*
* Copyright 2011 E.J.I.E., S.A.
*
* Licencia con arreglo a la EUPL, Versión 1.1 exclusivamente (la «Licencia»);
* Solo podrá usarse esta obra si se respeta la Licencia.
* Puede obtenerse una copia de la Licencia en
*
* http://ec.europa.eu/idabc/eupl.html
*
* Salvo cuando lo exija la legislación aplicable o se acuerde por escrito,
* el programa distribuido con arreglo a la Licencia se distribuye «TAL CUAL»,
* SIN GARANTÍAS NI CONDICIONES DE NINGÚN TIPO, ni expresas ni implícitas.
* Véase la Licencia en el idioma concreto que rige los permisos y limitaciones
* que establece la Licencia.
*/
package com.ejie.x38.serialization;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ejie.x38.util.StackTraceManager;
/**
* Deserializador de Jackson que permite la deserializacion de multiples
* entidades enviadas en un mismo JSON.<br>
*
* El deserializador recibe un JSON que contiene la representacion de las
* entidades que se deben deserializar junto a una propiedad que contiene la
* informacion necesaria para llevar a cabo el mapeo. <br>
*
* Esta informacion consiste en la correlacion entre las propiedades del JSON y
* de las clases Java. El nombre de esta propiedad sera rupEntityMapping.<br>
*
* Este es un ejemplo de un JSON que contiene varias entidades:<br>
* <br>
*
* <pre>
*
* {
* usuario:{
* id:"1",nombre:"nombre_usuario",apellido1:"apellido_usuario"
* },
* localidad:{
* code:"1",descEs:"descripcion_cast",descEu:"descripcion_eusk"
* },
* rupEntityMapping:{
* "usuario":"com.ejie.x21a.model.Usuario",
* "localidad":"com.ejie.x21a.model.Localidad"
* }
* }
*
* </pre>
*
* @author UDA
*
*/
public class MultiModelDeserializer extends
JsonDeserializer<Map<String, Object>> {
protected final Logger logger = LoggerFactory
.getLogger(MultiModelDeserializer.class);
/**
* Realiza la deserializacion del JSON
*
* @param jsonParser
* JsonParser que contiene el objeto JSON a deserializar y
* proporciona los metodos necesarios para su tratamiento.
* @param deserializationContext
* DeserializationContext.
* @return Map<String, Object> Mapa que contiene los model deserializados.
* @throws IOException
* Al producirse un error en el acceso a los datos del JSON.
* @throws JsonProcessingException
* Al producirse un error al procesar el JSON.
*/
@Override
public Map<String, Object> deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException,
JsonProcessingException {
// Creamos una JonFactory que nos permitira el procesado de los objetos JSON
JsonFactory jsonFactory = new MappingJsonFactory();
// Mapa de retorno en el que se van a almacenar los beans
Map<String, Object> mapaRetorno = new HashMap<String, Object>();
// Se obtiene una representacion en arbol del json a procesar
JsonNode jsonNodeTree = jsonParser.readValueAsTree();
// Recuperamos el objeto rupMultiModelMappings que define el mapeo de las entidades del json
JsonNode rupMultiModelMappingsNode = jsonNodeTree.get("rupEntityMapping");
// Recorremos todas las propiedades del json
Iterator<Entry<String, JsonNode>> fields = jsonNodeTree.fields();
while(fields.hasNext()){
// Procesamos cada propiedad del json
Entry<String, JsonNode> next = fields.next();
// Recuperamos el nombre de la propiedad
String propertyName = next.getKey();
// Comprobamos que la propiedad corresponde con una de las entidades para las que se ha definido un mapeo
if (rupMultiModelMappingsNode != null && rupMultiModelMappingsNode.has(propertyName)){
// Obtenemos el nombre de la clase Java a la que se debe de mapear la propiedad
String beanType = rupMultiModelMappingsNode.get(propertyName).asText();
// Creamos un nuevo jsonParser para procesar el json correspondiente a la entidad que se debe mapear
JsonParser entityJsonParser = jsonFactory.createParser(next.getValue().toString());
try {
// Se procesa el objeto json y se obtiene la instancia de la entidad correspondiente.
Object obj = entityJsonParser.readValueAs(Class.forName(beanType));
// Se anyade la entidad en el mapa de retorno
mapaRetorno.put(propertyName, obj);
} catch (ClassNotFoundException cnfe) {
// En caso de producirse un error en el procesado del json se lanza una excepcion
String stackTrace = StackTraceManager.getStackTrace(cnfe);
logger.error(StackTraceManager.getStackTrace(cnfe));
throw new JsonParseException(stackTrace,
entityJsonParser.getCurrentLocation());
}
}
}
// Se retorna el mapa de retorno que contiene las entidades mapeadas a partir del json procesado.
return mapaRetorno;
}
}