Defining the Mapping Relationships
This section covers the way to define a mapping from source to destination. These are defined in HOCON configuration files.
The code generation tool expects one or more HOCON configuration files to be present in a user-defined folder. Apart from
the .conf extension, there are no requirements about the naming. Each file, however, will either configure a mapping or
an enrichment.
Mapping to Mutable Target Objects
The below mapping and enrichment configurations apply to mapping mutable target objects
Mapping Configuration
Each pair of classes to be mapped will be defined by a configuration file containing the mappings key.
Bidirectional mapping can also be supported by adding bidirectional-mapping: true property to mapping conf file.
A basic mapping configuration will look like this:
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
]
Sometimes we want to map a class to a newer version of it, where the vast majority of attributes match. Maybe an array of elements, of which we are only interested in the first one, has turned into a scalar, or vice versa. More frequently, an attribute will have been removed.
In these cases, we can be concise and use implicit mappings (implicit-mapping: true) , and only specify the exceptions e.g. to exclude a removed attribute:
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
]
As previously said, this config will generate TestC → TestCv2 and TestCv2 → TestC mappers because bidirectional mapping is enabled. The apple object in the TestCv2 would be mapped to a single element array with mapped apple object.
Enrichment Configuration
Often times, the message to be sent to the target system carries needs to be enriched with fixed values coming from configuration, the system clock or simply hardcoded values.
The framework supports this by reading enrichment configuration from a file like the one below:
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"}
]
Enrichment is backed by an enrichment context, provided by the framework, that supports four types of enrichment sources:
| type | description | example |
|---|---|---|
|
constant value, on the |
|
|
generate a random alphanumeric token (32 characters) |
(no specification required) |
|
read a value from a HOCON configuration source |
|
|
use the current |
|
|
use the current date/time returned as an |
(no specification required) |
|
Populate a field from a value passed to |
Then call the method like this:
|
|
use the current date returned as a |
(no specification required) |
|
use the current date/time returned as an |
(no specification required) |
|
use the current date/time returned as a |
(no specification required) |
|
use the current date/time returned as a |
(no specification required) |
|
use the current date/time returned as an Icon IsoDateTime (for IPF API usage) |
(no specification required) |
Enrichment Configuration with Conditions per Individual Enrichment
You can include a new optional attribute called "enrichment-field-conditions" in each enrichment. This attribute provides the ability to control whether an enrichment is applied based on a specific condition expression.
The example below demonstrates two separate enrichments based on specific conditions. These enrichments have the following effects:
-
Enriching target.myIntegerProperty to 500 when source.myIntegerProperty == 100'
-
Enriching target.myStringProperty to 'updatedText' when source.myStringProperty == 'matchingText'
enrichment-target: com.ipf.payments.common.execution.enrichment.orika.testmodel.TestEnrichmentObject
// target-package is no longer used and does not need to be specified when using `orika-transformation-service-impl`
target-package: com.ipf.payments.common.execution.enrichment.orika.testmodel
enrichments: [
{
destination: "myIntegerProperty",
enrichment-type: value,
value: 500,
enrichment-field-conditions:[
"myIntegerProperty == 100",
]
},
{
destination: "myStringProperty",
enrichment-type: value,
value: "updatedText",
enrichment-field-conditions:[
"myStringProperty == 'matchingText'"
]
}
]