Definir las relaciones de mapeo
Esta sección cubre la forma de definir un mapeo de origen a destino. Estas se definen en archivos de configuración HOCON (.conf).
.conf vs .mconf
Estas definiciones también pueden definirse como archivos con el formato .mconf.
La estructura del archivo mconf tiene soporte de lenguaje integrado a través del IPF Idea Plugin, que proporciona restricciones específicas del dominio y características más allá del soporte ofrecido por plugins Hocon de terceros; elegimos una extensión específica para no solaparnos con el soporte existente del lenguaje HOCON.
Características incluyen:
-
Autocompletado y validación de rutas de campos
-
Validación condicional de claves
-
Comprobación de claves duplicadas
Y mucho más.
La estructura del archivo y la sintaxis son actualmente exactamente iguales entre los dos formatos salvo por un detalle.
La sintaxis de acceso a arrays en rutas de campos en hocon es de la forma a.b.0.c mientras que la sintaxis equivalente en mconf sería a.b[0].c
|
La herramienta de generación de código espera uno o más archivos de configuración HOCON presentes en una carpeta definida por el usuario. Aparte de
la extensión .conf o .mconf, no hay requisitos sobre el nombre. Sin embargo, cada archivo configurará un mapeo o
un enriquecimiento.
| En segundo plano, los archivos mconf se traducen a archivos conf antes de ser procesados por la herramienta de generación de código. |
Mapeo a objetos destino mutables
Las configuraciones de mapeo y enriquecimiento siguientes aplican al mapeo de objetos destino mutables
Configuración de mapeo
Cada par de clases a mapear se definirá mediante un archivo de configuración que contenga la clave mappings.
El mapeo bidireccional también puede admitirse añadiendo la propiedad bidirectional-mapping: true al archivo de configuración de mapeo.
Una configuración básica de mapeo tendrá este aspecto:
source-class: com.ipf.example.model.TestA # class to read
destination-class: com.ipf.example.model.TestB # class to produce
target-package: com.ipf.example.mapping # package to generate
target-class-name: TestAToTestBCustomiser # name of the mapper class to generate
mappings: [
{ source: foo, destination: bar } # just map this pair
# { source: moreFoo, destination: moreBar } # ...any other pairs would go here
]
A veces queremos mapear una clase a una versión más reciente de la misma, donde la gran mayoría de atributos coinciden. Quizá un array de elementos, de los cuales sólo nos interesa el primero, se ha convertido en un escalar, o viceversa. Con más frecuencia, se habrá eliminado un atributo.
En estos casos, podemos ser concisos y usar mapeos implícitos (implicit-mapping: true), y sólo especificar las excepciones, p. ej., para excluir un atributo eliminado:
source-class: com.ipf.example.model.v1.TestC
destination-class: com.ipf.example.model.v2.TestCv2
target-package: com.ipf.example.mapping
target-class-name: TestCToTestCv2Customiser
implicit-mapping: true # match attributes by name
bidirectional-mapping: true
mappings: [
{ source: foo2, excluded: true } # exclude an attribute from mapping
{ source: apples.0, destination: apple } # map first apple in array of apples
{ source: bananas.0, destination: banana } # map first banana in array of bananas
{ source: farmer, destination: farmers.0 } # it also works the other way around
]
Como se dijo anteriormente, esta configuración generará mapeadores TestC → TestCv2 y TestCv2 → TestC porque el mapeo bidireccional está habilitado. El objeto apple en TestCv2 se mapeará a un array de un solo elemento con el objeto apple mapeado.
Configuración de enriquecimiento
A menudo, el mensaje que se enviará al sistema destino necesita ser enriquecido con valores fijos provenientes de la configuración, el reloj del sistema o simplemente valores codificados.
El framework admite esto leyendo la configuración de enriquecimiento de un archivo como el siguiente:
enrichment-target: com.ipf.example.model.TestA # what class to enrich
target-package: com.ipf.example.mapping
enrichments: [
{destination: version, enrichment-type: value , value: 100L}
{destination: id, enrichment-type: randomAlphaNumeric}
{destination: special, enrichment-type: config-value, path: "get.me"}
{destination: date, enrichment-type: from-instant, format: "dd/MM/yyyy"}
]
El enriquecimiento se basa en un enrichment context, proporcionado por el framework, que admite cuatro tipos de orígenes de enriquecimiento:
| type | description | example |
|---|---|---|
|
valor constante, en la propiedad |
|
|
genera una cadena alfanumérica con una longitud dada |
|
|
lee del archivo de configuración de la aplicación, en la ruta indicada por |
|
|
formatea el instante actual como cadena con el patrón dado |
|
Mapeo a objetos destino inmutables
Cuando el objeto destino es inmutable, el mapeo requiere el uso de un builder. En este caso, además de los tipos de origen y destino, hay que indicar el tipo del builder del destino.