domingo, 11 de enero de 2015

Mapeo entre Beans en tiempos de JSON. Como mapear entre JSON y beans de Java usando Jackson y Dozer


Recientemente he tenido la necesidad de integrar un nuevo servicio externo datos en formato JSON y tener que acomodarlos en el conglomerado de beans de Java ya existente previamente en la aplicación que lo usaría. Estos últimas clases tienen una estructura definida hace años y reciben datos de muchas otras fuentes. El nuevo JSON difiere en estructura, pero debe de convertirse en uno de los viejos objetos Java sin que nadie lo note.

{

"mapid":333,

"mapNombre":"Jose Perez",
"mapRelated":[
"A",
"B",
"C"
],
"mapInternalA":{
"mapInternalA":"id1",
"mapInternalA1":{
"theMostInternal":4
}
},
"mapcompactA":{
"id":"fgfg",
"name":"gfdgfd"
},
"mapB":3424,
"mapC":23
}


Para el mapeo JSON-Java usamos Jackson librería potente y rápida, pero que sin embargo para nuestro caso actual presenta un problema. No esta preparada para modificar la estructura de los datos que esta mapeando. Esto viene a querer decir que teniendo un JSON, se necesitaría tener un objeto Java completamente igual para poder efectuar el mapeo. 

//No es este objeto el que necesitaba

public class A {

Integer id;
String name;
List<String> related;
InternalA internalA;
CompactInternalA compactA;
}


Dado que mi caso no era así, estaba claro que necesitaríamos dos fases de mapeo, esta ya mencionada y una segunda usando Dozer que si que es una librería especializada en mapear dos beans de Java no importa lo distintos que sean. Solo necesita un archivo XML que indique las equivalencias entre ellos para poder hacer su magia. 

<mapping type="one-way">

<class-a map-get-method="getValue">es.santescas.NestedAccessMap</class-a>

<class-b>es.santescas.dto.A</class-b>
<field>
<a key="mapid">this</a>
<b>id</b>
</field>
<field>
<a key="mapNombre">this</a>
<b>name</b>
</field>
<field>
<a key="mapRelated">this</a>
<b>related</b>
</field>
<field>
<a key="mapInternalA.mapInternalA">this</a>
<b>internalA.internalA</b>
<a-hint>java.lang.String</a-hint>
</field>
<field>
<a key="mapInternalA.mapInternalA1.theMostInternal">this</a>
<b>internalA.internalA1.theMostInternal</b>
</field>
<field map-id="CompactReaalyInternalA">
<a key="mapcompactA">this</a>
<b>compactA</b>
<a-hint>java.util.Map</a-hint>
<b-hint>es.santescas.dto.CompactInternalA</b-hint>
</field>
</mapping> 


Todo esto nos dejaba con un proceso mas o menos así.



Sin embargo la idea de mantener la información de mapeo en 2 lugares distintos no me gustaba. Si algún campo de la fuente cambiaba no solo sería necesario cambiar el conjunto de beans 1 sino que también el archivo XML. Los beans 1 debián morir.

En este punto entra en juego una cualidad de Dozer, quizás poco explorada y es que es casi tan potente convirtiendo entre dos objetos beans de Java como entre un mapa y un objeto. Usando esto fue posible eliminar el conjunto de objetos A y tener definido información del mapeo solo en el archivo XML.



El código fuente del ejemplo completo puede ser encontrado en:
Repo de Github

No hay comentarios:

Publicar un comentario