28/06/2017Artículo original
Hoy vamos a hablar de cómo usar la librería Jackson para mapear fácilmente un Json a objetos Java.
Declarar dependencia
El primer paso es declarar la dependencia en el proyecto, en éste caso usando maven, en el fichero pom.xml añadimos:
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.4.4</version></dependency>
Hecho esto, ya es posible usar la librería en el proyecto.
Introducción a Jackson
Veamos una guía de uso rápido de jackson. Para los siguientes ejemplos supondremos la siguiente clase:
// Nota: Para atributos públicos, no es necesario usar getters y setters.publicclassMiClase{publicStringnombre;publicintedad;// Nota: Si los campos son private o protected, es obligatorio usar getters y setters.// Es recomendable crear el constructor por defecto}
Supongamos también el siguiente json, almacenado en un fichero mijson.json:
{"nombre":"Alicia","edad":13}
Es necesario crear un ObjectMapper, y lo típico es hacerlo estático para re-utilizarlo a lo largo de la aplicación. Un buen lugar para él sería un clase Constant y declarar el ObjectMapper así:
publicstaticfinalObjectMapperJSON_MAPPER=newObjectMapper();
Json a Objeto Java (Des-Serializar)
Para des-serializar el json y crear el objeto en Java:
MiClaseobjeto=JSON_MAPPER.readValue(newFile("mijson.json",MiClase.class);// oMiClaseobjeto=JSON_MAPPER.readValue(newURL("https://ruta/a/mijson.json",MiClase.class);
Objeto Java a Json (Serializar)
Para realizar el proceso inverso, basta con:
JSON_MAPPER.writeValue(newFile("mijson.json"),objeto);// ó:byte[]jsonBytes=JSON_MAPPER.writeValueAsBytes(objeto);// ó:StringjsonString=JSON_MAPPER.writeValueAsString(objeto);
Generalizar el tipo de objeto a des-serializar
Al trabajar con una API, serializar y des-serializar objetos es una tarea común, una forma de generalizar el proceso puede ser la siguiente.
Supongamos que nuestra api devuelve arrays de objetos, por ejemplo una lista de Personas, una lista de productos etc. El modelo en Java sería el siguiente:
publicclassPersona{privateStringNombre;privateStringApellidos;privateintDNI;publicPersona(){}publicStringgetNombre(){returnNombre;}publicvoidsetNombre(StringNombre){this.Nombre=Nombre;}publicStringgetApellidos(){returnApellidos;}publicvoidsetApellidos(StringApellidos){this.Apellidos=Apellidos;}publicintgetDNI(){returnDNI;}publicvoidsetDNI(intDNI){this.DNI=DNI;}}
publicclassProducto{privateStringNombre;privateStringModelo;privateintprecio;privatefloatvaloracion;publicProducto(){}publicStringgetNombre(){returnNombre;}publicvoidsetNombre(StringNombre){this.Nombre=Nombre;}publicStringgetModelo(){returnModelo;}publicvoidsetModelo(StringModelo){this.Modelo=Modelo;}publicintgetPrecio(){returnprecio;}publicvoidsetPrecio(intprecio){this.precio=precio;}publicfloatgetValoracion(){returnvaloracion;}publicvoidsetValoracion(floatvaloracion){this.valoracion=valoracion;}}
Los arrays en json:
//Personas[{"Nombre":"Bob","Apellidos":"BobBob","DNI":123456789},{"Nombre":"Alice","Apellidos":"Alice","DNI":123456789},{"Nombre":"Foo","Apellidos":"bar","DNI":123456789}]//Productos[{"Nombre":"Tele","Modelo":"modelo1","Precio":120,"Valoracion":2.5},{"Nombre":"Tele2","Modelo":"Modelo2","Precio":150,"Valoracion":5},{"Nombre":"Tele3","Modelo":"Modelo3","Precio":520,"Valoracion":5}]
Con estos datos, queremos des-serializar el json en un ArrayList del tipo de clase que sea, en éste caso ArrayList
ArrayList<Persona>personas=JSON_MAPPER.readValue(newFile("personas.json"),JSON_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class,Persona.class));// Para productosArrayList<Producto>productos=JSON_MAPPER.readValue(newFile("productos.json"),JSON_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class,Producto.class));
Ahora bien, si tenemos más modelos, a parte de Personas y Productos, y normalmente, los json se obtienen mediante la API, vamos a repetir un montón de código. Podríamos crear un método genérico para mapear json a objetos java, como el siguiente:
publicstatic<T>List<T>getList(Stringurl,Class<T>clazz){HttpClientclient=HttpClientBuilder.create().build();HttpGetgetRequest=newHttpGet(url);getRequest.setHeader(HttpHeaders.ACCEPT,MediaType.APPLICATION_JSON);List<T>data=null;HttpResponseresponse;try{response=client.execute(getRequest);data=Constants.JSON_MAPPER.readValue(response.getEntity().getContent(),JSON_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class,clazz));}catch(IOExceptionex){logger.error("Error retrieving "+clazz.getName()+" "+ex.toString());}returndata;}
Éste método se usaría así:
// Para personasArrayList<Persona>personas=getList(URLDELAAPIPARAOBTENERPERSONAS,Persona.class);// Para productosArrayList<Producto>personas=getList(URLDELAAPIPARAOBTENERPRODUCTOS,Producto.class);
Conclusión
La librería Jackson de fasterXML ofrece muchísimas más cosas de las vistas aquí. El uso de anotaciones por ejemplo permite ignorar ciertos valores de un modelo, no permitir nulos etc, para más información visita las referencias.