Mappers


Mappers

Mapper definitions that transform source data fields to Pricefx format.

When to Use

Mapper type

Use when

API method

loadMapper

Bulk load / replace data

pfx-api:loaddata, pfx-api:loaddataFile

integrateMapper

Upsert (insert or update by key)

pfx-api:integrate

multilevelMapper

Nested/hierarchical data

Multi-level operations


Attribute

Details

Purpose

Define how source fields map to Pricefx fields (rename, transform, convert types)

Format

XML — <mappers> wrapper with one mapper element inside (<loadMapper>, <integrateMapper>, <mapper>)

Naming

By entity or function: product-mapper.xml, customer-mapper.xml. One mapper per file.

Loaded by

Spring context at startup — registered as beans by mapper ID


Mapper Types

Type

Use Case

loadMapper

Import data via pfx-api:loaddata — bulk load

integrateMapper

Upsert data via pfx-api:integrate — match by business keys

mapper

Generic transformation


Expression Types

Each mapping row uses an expression type to define how the output value is produced:

Expression Type

Description

Example

body

Direct field mapping — copies the value of in field to out field

<body in="sku" out="sku"/>

simple

Apache Camel Simple expression language

<simple expression="${date:now:yyyy-MM-dd}" out="attribute3"/>

groovy

Groovy script — full language support, body variable is the current row

<groovy expression="body.price?.toBigDecimal()" out="attribute1"/>

constant

Static literal value

<constant expression="ACTIVE" out="attribute2"/>

header

Reads a value from a Camel message header

<header expression="CamelFileName" out="attribute4"/>

property

Reads a value from a Camel exchange property

<property expression="batchId" out="attribute5"/>


Attributes Reference

Mapper element attributes

Attribute

Type

Required

Description

id

string

Yes

Unique bean ID, referenced by mapper= in route URIs

convertEmptyStringToNull

boolean

No

When true, empty strings are converted to null

includeUnmappedProperties

boolean

No

When true, source fields not listed in the mapper are passed through unchanged. Useful when you want to map everything 1:1 without listing each field

excludeProperties

string

No

Comma-separated list of source fields to exclude from the output. Used with includeUnmappedProperties="true" to pass through all fields except specific ones

skipInvalidRecords

boolean

No

When true, records that fail validation (missing required fields, type conversion errors) are skipped instead of failing the entire batch

Mapping row attributes

Attribute

Type

Required

Description

in

string

Depends

Source field name (required for body type)

out

string

Yes

Target Pricefx field name

expression

string

Depends

Expression string (required for simple, groovy, constant, header, property)

converterExpression

string

No

Built-in converter name (e.g., stringToDecimal, stringToInteger, stringToBoolean, stringToDate). Supports optional parameters: stringToInteger('20')

converter

string

No

Reference to a custom converter Spring bean defined in your beans XML. Use this only for custom converters, not built-in ones.


Built-in Converter Expressions

Use converterExpression for built-in type converters. Do not use converter for these — converter is reserved for custom Spring bean references.

Expression

Description

stringToInteger

Converts string to integer. Optional default: stringToInteger('0')

stringToDecimal

Converts string to BigDecimal

stringToDouble

Converts string to double

stringToBoolean

Converts string to boolean

stringToDate

Converts string to date

stringToDateTime

Converts string to date-time

stringToNumber

Generic string-to-number conversion

stringToNumberUS

Number conversion using US locale

stringToNumberGER

Number conversion using German locale

converterExpression vs converter:

  • converterExpression="stringToDecimal" — use this for built-in converters listed above

  • converter="myCustomConverter" — use this only when referencing a custom converter bean defined in your beans XML


Examples

mappers/product-mapper.xml

One mapper per file, wrapped in <mappers>:

XML
<mappers>
    <loadMapper convertEmptyStringToNull="true" id="product-mapper">
        <body in="sku" out="sku"/>
        <body in="product_name" out="label"/>
        <body in="unit_of_measure" out="unitOfMeasure"/>
        <body in="currency" out="currency"/>
        <body in="price" out="attribute1" converterExpression="stringToDecimal"/>
        <constant expression="ACTIVE" out="attribute2"/>
    </loadMapper>
</mappers>

mappers/product-upsert-mapper.xml

XML
<mappers>
    <integrateMapper id="product-upsert-mapper">
        <body in="sku" out="sku"/>
        <body in="product_name" out="label"/>
        <body in="price" out="attribute1" predicate="body.price != null &amp;&amp; body.price.toBigDecimal() > 0"/>
        <simple expression="${date:now:yyyy-MM-dd}" out="attribute3"/>
    </integrateMapper>
</mappers>

integrateMapper-specific attributes on mapping rows:

Attribute

Type

Description

predicate

string

Groovy expression that must evaluate to true for this field to be updated. Only applies to <body>, <header>, <property> elements inside <integrateMapper>. Example: predicate="body.price != null"

predicateRef

string

Reference to a Spring bean implementing Predicate interface. Alternative to inline predicate expression for complex logic

mappers/customer-mapper.xml

XML
<mappers>
    <loadMapper id="customer-mapper">
        <body in="customer_id" out="customerId"/>
        <body in="customer_name" out="label"/>
        <groovy expression="body.region?.toUpperCase()" out="attribute1"/>
        <header expression="CamelFileName" out="attribute4"/>
        <property expression="batchId" out="attribute5"/>
    </loadMapper>
</mappers>

Converter Best Practices

When to Use converterExpression vs. Groovy

Scenario

Use

Example

Standard type conversion

converterExpression

stringToDecimal(us)

Locale-specific parsing

converterExpression with locale

stringToDate(yyyy-MM-dd)

Conditional logic

groovy expression

body.field == '99999999' ? '99991231' : body.field

Header/property access

groovy expression

headers.countryCode

Chained transformations

groovy expression

body.field?.trim()?.toUpperCase()

Prefer converterExpression when a built-in converter exists. Only use Groovy for logic that converters can't handle.

Decimal Handling by Locale

XML
<!-- US format: 1,234.56 -->
<body converterExpression="stringToDecimal(us)" in="Price" out="attribute1"/>

<!-- German format: 1.234,56 -->
<body converterExpression="stringToDecimal(de)" in="Preis" out="attribute1"/>

Always specify the locale explicitly. The default locale depends on the JVM and may differ between environments.

Date Handling

XML
<!-- ISO format -->
<body converterExpression="stringToDate(yyyy-MM-dd)" in="StartDate" out="attribute2"/>

<!-- US format -->
<body converterExpression="stringToDate(MM/dd/yyyy)" in="StartDate" out="attribute2"/>

<!-- Conditional date with Groovy -->
<groovy expression="body.EndDate == '99999999' ? '9999-12-31' : body.EndDate"
        converterExpression="stringToDate(yyyy-MM-dd)" out="attribute3"/>

skipInvalidRecords Behavior

XML
<loadMapper id="myMapper" skipInvalidRecords="true" convertEmptyStringToNull="true">

When skipInvalidRecords="true":

  • Records that fail converter parsing are silently skipped (not loaded)

  • A warning is logged per skipped record

  • Useful for dirty data where a few bad records shouldn't block the whole import

  • Risk: silently losing data — monitor PfxTotalInputRecordsCount vs. expected count

When convertEmptyStringToNull="true":

  • Empty strings "" become null in the Pricefx object

  • Without this, empty strings may overwrite existing values with blanks

  • Recommended default: true for most import scenarios


Attribute Value Truncation

When loading data into extension tables (PX, CX, SX), string attribute values may be automatically truncated to prevent Pricefx API errors caused by values exceeding the column size limit.

How It Works

Pricefx extension tables have a fixed database column size for each attribute (typically 255 characters). However, when an extension table has many attributes, the available column size per attribute decreases. The truncation feature dynamically adjusts the maximum allowed string length based on the actual number of attributes configured in the extension table.

The decision logic:

  1. IM fetches the extension table metadata from Pricefx (e.g., configurationmanager.get/productextension) to determine the number of attributes (numberOfAttributes).

  2. If numberOfAttributes >= threshold → values are truncated to max.size characters.

  3. If numberOfAttributes < threshold → values are truncated to the standard 255 character limit.

Configuration

Property

Default

Description

integration.mappers.<TYPE>.attributes.truncate.max.size

70

Maximum string length when the extension table has many attributes (at or above the threshold)

integration.mappers.<TYPE>.attributes.truncate.threshold

50

Number of attributes at which the reduced max.size limit kicks in

integration.mappers.extended.attributes.max.size

10000000

Maximum size for JLTV/JLTV2 extended attribute values

Where <TYPE> is one of: PX, CX, SX.

Default values:

integration.mappers.PX.attributes.truncate.max.size=70
integration.mappers.PX.attributes.truncate.threshold=50
integration.mappers.CX.attributes.truncate.max.size=70
integration.mappers.CX.attributes.truncate.threshold=50
integration.mappers.SX.attributes.truncate.max.size=70
integration.mappers.SX.attributes.truncate.threshold=50

Example

Consider a PX table called Costs with numberOfAttributes=60 (threshold is 50):

  • Since 60 >= 50, the max.size of 70 applies

  • Any string attribute value longer than 70 characters is silently truncated to 70 characters via substring(0, 70)

If the same table had only 30 attributes:

  • Since 30 < 50, the standard 255 character limit applies

Important Notes

  • Truncation applies only to string values. Numbers, booleans, and nulls are not affected.

  • Truncation is a simple substring(0, maxLength) — no ellipsis or warning is added.

  • The extension metadata is cached and refreshed every 10 minutes (configurable via integration.schedulers.mapper-truncate.cache.ms).

  • Standard object types (P, C, SL) always use the 255 character limit — these properties have no effect on them.

  • Applies to loaddata, integrate, and save operations.

Common Pitfalls

  • Mapper IDs must be unique and match the mapper= parameter in route URIs

  • Each file must have the <mappers> wrapper element around the mapper definition — do NOT use <beans>, <beans:beans>, or XML declarations

  • Use groovy expressions for complex transformations, body for simple field mapping

  • Built-in type converters (e.g., stringToDecimal) must use the converterExpression attribute, not converter. The converter attribute is only for custom Spring bean references.

  • One mapper per file — do not put multiple mappers in a single file

See Also

  • Routes — Mappers are referenced in routes via mapper= parameter

  • Filters — Filters select data, mappers transform it

  • Converters — Type converters used in mapper expressions

  • pfx-api Component — loaddata and integrate methods use mappers