Code Generation y utilice
Esta página cubrirá cómo generar el mapping código y luego, posteriormente, cómo utilizar esos mappers.
Generando el mapping informe
A veces nos enfrentamos a la abrumadora tarea de configurar el mapping entre dos clases similares, grandes y profundas estructuras (como dos versiones diferentes de ISO 20022), por lo que consideramos utilizar implicit mapping pero le gusta la idea de mantener el control. En tal caso, sería bueno saber qué es lo que realmente mappings sería aplicado. Afortunadamente, el marco incluye un Maven plugin hacer precisamente eso:
-
pom.xml
<plugin>
<groupId>com.iconsolutions.ipf.core.mapper</groupId>
<artifactId>orika-transformation-report-plugin</artifactId>
<version>${icon-mapper.version}</version>
<dependencies>
<!-- Do not forget to list your domain class libraries here -->
<dependency>
<groupId>com.example</groupId>
<artifactId>my-iso20022-domain</artifactId>
<version>1. 0. 0</version>
</dependency>
</dependencies>
</plugin>
Este complemento se ejecutará en la línea de comandos:
$ mvn orika-transformation-report:mapping-report \
-Dsource=eba.scti.iso.std.iso._20022.tech.xsd.pacs_002_001_003. FIToFIPaymentStatusReportV03 \
-Ddestination=iso.std.iso._20022.tech.xsd.pacs_002_001_007. FIToFIPaymentStatusReportV07
produciendo una salida compuesta de dos partes. La primera parte explicará qué es un implicit mapping resultaría en:
Mapping report for eba.scti.iso.std.iso._20022.tech.xsd.pacs_002_001_003. FIToFIPaymentStatusReportV03 to iso.std.iso._20022.tech.xsd.pacs_002_001_007. FIToFIPaymentStatusReportV07
Mapped from source
grpHdr (SCTInstGroupHeader5) to grpHdr (GroupHeader53) (1)
msgId (String) to msgId (String) (2)
creDtTm (XMLGregorianCalendar) to creDtTm (XMLGregorianCalendar)
instgAgt (SCTInstBranchAndFinancialInstitutionIdentification3) to instgAgt (BranchAndFinancialInstitutionIdentification5)
finInstnId (SCTInstFinancialInstitutionIdentification5Choice) to finInstnId (FinancialInstitutionIdentification8)
bic not mapped (3)
bicfi in target but not mapped from source
clrSysMmbId in target but not mapped from source (4)
nm in target but not mapped from source
pstlAdr in target but not mapped from source
othr in target but not mapped from source
brnchId in target but not mapped from source
..
-
Coincidencia de diferentes clases por nombre
-
Válido mapping
-
bicdebe ser mapeado abicfibelow -
Campos que faltan una correspondencia directa en la clase de origen
La segunda parte del informe contendrá un mapping sugerencia, para comenzar con:
source-class: eba.scti.iso.std.iso._20022.tech.xsd.pacs_002_001_003. FIToFIPaymentStatusReportV03
destination-class: iso.std.iso._20022.tech.xsd.pacs_002_001_007. FIToFIPaymentStatusReportV07
implicit-mapping: true
target-class-name: ADD YOUR DESIRED CLASS NAME HERE # (1)
mappings: [
{source: NO SOURCE DETECTED, destination: splmtryDatas, type: List} # (2)
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.brnchId, type: BranchData2}
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.finInstnId.bicfi, type: String}
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.finInstnId.clrSysMmbId, type: ClearingSystemMemberIdentification2}
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.finInstnId.nm, type: String}
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.finInstnId.pstlAdr, type: PostalAddress6}
{source: NO SOURCE DETECTED, destination: grpHdr.instgAgt.finInstnId.othr, type: GenericFinancialIdentification1}
{source: grpHdr.instgAgt.finInstnId.bic, destination: NO DESTINATION MATCHED, type: String}
//..
]
-
El nombre de la clase objetivo es necesario. También, un
target-packagedebe ser añadido. -
Esta es la lista de faltantes mappings de acuerdo con Orika. Cambie según sea necesario.
Generando el Java Código
Para generar el Java código, el proyecto del usuario deberá utilizar Maven y configure lo siguiente Maven plugin:
-
pom.xml
<plugin>
<groupId>com.iconsolutions.ipf.core.mapper</groupId>
<artifactId>orika-transformation-generation-plugin</artifactId>
<version>${icon-mapper.version}</version>
<executions>
<execution>
<id>make-mappers</id>
<goals>
<goal>generate-code</goal>
</goals>
<configuration>
<!-- location of the HOCON files -->
<mapperPath>${project.basedir}/src/main/mappers</mapperPath>
<!-- where to place generated sources -->
<generatedMappersPath>${project.build.directory}/generated-sources/java</generatedMappersPath>
<!-- where to place generated test-sources -->
<generatedMappersTestPath>${project.build.directory}/generated-test-sources/java </generatedMappersTestPath>
<!-- the Java package they will belong to -->
<targetPackage>com.ipf.example.mapping</targetPackage>
<!-- Name the generated class that will instantiate our universal mapping service -->
<transformationServiceFactoryName>ExampleTransformationFactory</transformationServiceFactoryName>
<!-- You can code your own Orika mappings if you wish, just place them in the target package and list them below -->
<additionalCustomisers>
<additionalCustomiser>MySpecialCustomiser</additionalCustomiser>
<additionalCustomiser>MyPreciousCustomiser</additionalCustomiser>
</additionalCustomisers>
</configuration>
</execution>
</executions>
<dependencies>
<!--
The plugin needs to depend on your domain classes to generate the code.
List all domain model libraries as dependencies here.
-->
<dependency>
<groupId>com.iconsolutions.ipf.core.mapper</groupId>
<artifactId>example-model</artifactId>
<version>1. 0. 0</version>
</dependency>
</dependencies>
</plugin>
Cuando se ejecuta la compilación y se lleva a cabo el objetivo del complemento, un número de
Las clases customiser se producen para ambos mappings y enriquecimientos.
Estas clases generadas interactúan con el Orika mapping API implementar
el actual mappings. Custom Se pueden escribir utilizando el Orika API
y luego se añadió a la <additionalCustomisers /> above.
Saltar Java Prueba Code Generation
Para deshabilitar la prueba code generation conjunto <skipTestsGeneration>true<skipTestsGeneration/>.
Por defecto,skipTestsGeneration es falso, lo que requiere generatedMappersTestPath tener un valor.
Ejemplo de configuración mostrado a continuación:
-
pom.xml
<configuration>
<!-- location of the HOCON files -->
<mapperPath>${project.basedir}/src/main/mappers</mapperPath>
<!-- where to place generated sources -->
<generatedMappersPath>${project.build.directory}/generated-sources/java</generatedMappersPath>
<!-- When true the test code is not generated-default is set to false -->
<skipTestsGeneration>true</skipTestsGeneration>
<!-- Not required when skipping test code generation -->
<!-- <generatedMappersTestPath>${project.build.directory}/generated-test-sources/java </generatedMappersTestPath> -->
<!-- the Java package they will belong to -->
<targetPackage>com.ipf.example.mapping</targetPackage>
<!-- Name the generated class that will instantiate our universal mapping service -->
<transformationServiceFactoryName>ExampleTransformationFactory</transformationServiceFactoryName>
<!-- You can code your own Orika mappings if you wish, just place them in the target package and list them below -->
<additionalCustomisers>
<additionalCustomiser>MySpecialCustomiser</additionalCustomiser>
<additionalCustomiser>MyPreciousCustomiser</additionalCustomiser>
</additionalCustomisers>
</configuration>
Escribiendo Adicional Customisers
Desde Orika la documentación de 's:
Orika uses a declarative Java-based configuration of mappings from one class to another, whereby you define which fields from one type need to be matched up with which fields from another using a fluent-style API.
Esto significa que podemos aprovechar la flexibilidad total de la Orika marco para abordar casos extremos, tales como:
class TestA {
private String foo;
private String bar;
//..
}
class TestB {
public TestB(String arg1, String arg2) {
//..
}
}
class MyCustomiser implements OrikaCustomiser {
public void customise(MapperFactory mapperFactory) {
mapperFactory.classMap(TestA.class, TestB.class)
.constructorB("foo","bar") // TestA's foo and bar used to instantiate TestB
//..
.register();
}
}
class TestA {
private Map<String, String> address;
//..
}
class TestB {
private String firstLine;
private String secondLine;
//..
}
class MyCustomiser implements OrikaCustomiser {
public void customise(MapperFactory mapperFactory) {
mapperFactory.classMap(TestA.class, TestB.class)
.field("address['line1']", "firstLine")
.field("address['town']", "secondLine")
.register();
}
}
Vea el Orika guía de Declarativo Mapping Configuración utilizando la API ClassMapBuilder de estilo fluido' para más detalles y casos de uso.
Uso del Código Generado
En el previous section, mostramos cómo configurar el code generation. Parte de la tarea fue elegir un nombre para un Java clase que instanciaría nuestro mapping servicio:
<transformationServiceFactoryName>ExampleTransformationFactory</transformationServiceFactoryName>
Nuestro generado ExampleTransformationFactory la clase se utilizará para crear un TransformationService,
que es efectivamente nuestro _universal_mapping servicio:
.Instantiating a TransformationService
TransformationService transformationService = new ExampleTransformationFactory(
DefaultEnrichmentContext.builder().build()
).transformationService();
Este único, genérico mapper solo cubrirá todo el mapping y configuración de enriquecimiento. Dado que es sin estado, compartir una única instancia o ejecutar múltiples es una cuestión de elección de diseño.
Como podemos ver en el ejemplo anterior, la fábrica de servicios necesita un contexto de enriquecimiento
y el marco nos proporciona una implementación predeterminada llamada DefaultEnrichmentContext, donde:
-
se utiliza un reloj del sistema UTC
-
La configuración HOCON se lee de archivos llamados " ipf.conf "
-
los tokens generados aleatoriamente tienen 32 caracteres de longitud
Estos tres aspectos pueden configurarse como se observa en el ejemplo a continuación:
.Configuring the default enrichment context
DefaultEnrichmentContext.builder()
.withClock(Clock.system(ZoneId.of("GMT+2"))) (1)
.withConfigProvider(new SimpleConfigProvider(
ConfigFactory.load("my-application.conf"))) (2)
.withRandomAlphaNumericGenerator(new RandomAlphanumericGenerator(16)); (3)
| 1 | cambie la zona horaria |
| 2 | proporcione una fuente diferente de configuración |
| 3 | cambie la longitud del token |
Ahora que tenemos un TransformationService, analicemos lo que podemos hacer con ello:
.Mapping an object to a different class
TestA testA = new TestA();
testA.setFoo("something magic");
TestB testB = transformationService.map(testA, TestB.class);
assertThat(testB.getBar(), is("something magic"));
.Enriching an object
TestB testB = transformationService.enrich(new TestB());
// testB has been applied any configured enrichment
.Mapping to a target class then enrich
TestA testA = new TestA();
testA.setFoo("something magic");
TestB testB = transformationService.mapThenEnrichWithDefault(testA, TestB.class);
// testB has been both mapped from testA and applied any configured enrichment