Overview
The <integrateMapper> element is used for upsert (insert-or-update) operations in Pricefx. Unlike <loadMapper>, which is designed for bulk data loads that replace data, <integrateMapper> uses business keys to match existing records and update them, or insert new ones if no match is found. This is the recommended pattern for incremental synchronization scenarios.
Complete XML Examples
Basic Upsert with Business Key
The business key fields (like sku) identify existing records to update:
<mappers>
<integrateMapper id="productUpsertMapper" includeUnmappedProperties="false">
<!-- Business key: matches existing products by SKU -->
<body in="sku" out="sku"/>
<!-- Fields to update -->
<body in="name" out="label"/>
<body in="price" out="attribute1"/>
<body in="category" out="attribute2"/>
</integrateMapper>
</mappers>
IntegrateMapper with Converters and Expressions
Standard converters (stringToDecimal, stringToNumber, etc.) are pre-registered by Spring — reference them by name directly. For custom converters that need constructor arguments, define a bean in the beans/ folder:
<mappers>
<integrateMapper id="integrateCsvMapper" includeUnmappedProperties="false">
<!-- Static country code for all records -->
<simple expression="CZ" out="country"/>
<!-- Business key -->
<body in="sku" out="sku"/>
<!-- Date field for tracking -->
<body in="lastUpdateDate" out="updatedDate"/>
<!-- Price with type conversion (stringToDecimal is pre-registered) -->
<body in="resultPrice" out="price" converter="stringToDecimal"/>
<!-- Additional fields -->
<body in="attribute1" out="manufacturer"/>
<body in="label" out="label"/>
</integrateMapper>
</mappers>
If you need a custom converter with constructor arguments (e.g., StringRight), define it in beans/converters.xml -- never inline in the mapper file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stringRight7"
class="net.pricefx.integration.mapper.converter.StringRight">
<constructor-arg value="7"/>
</bean>
</beans>
IntegrateMapper with includeNulls
When includeNulls="true", null values in the source will explicitly set the target field to null (clearing existing data):
<mappers>
<integrateMapper id="fullSyncMapper" includeNulls="true">
<body in="inAttribute1"/>
<body in="inAttribute2" out="outAttribute2"/>
<body in="inAttribute3" out="outAttribute3"/>
<body in="inAttribute4" out="outAttribute4"/>
<simple expression="simple_expression" out="outAttribute5"/>
<groovy expression="groovy_expression" out="outAttribute6"/>
</integrateMapper>
</mappers>
IntegrateMapper with Condition Filter
Use a condition parameter on pfx-api:integrate to control which existing records are matched for update. The filter and mapper are defined in separate files:
filters/active-products-condition.xml:
<filters>
<filter id="activeProductsCondition">
<and>
<criterion fieldName="attribute1" operator="notNull"/>
</and>
</filter>
</filters>
mappers/conditional-upsert-mapper.xml:
<mappers>
<integrateMapper id="conditionalUpsertMapper" includeUnmappedProperties="false">
<body in="sku" out="sku"/>
<body in="name" out="label"/>
<body in="price" out="attribute1"/>
</integrateMapper>
</mappers>
Usage in a route:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="integrateProducts">
<from uri="direct:integrateProducts"/>
<to uri="pfx-api:integrate?objectType=P&mapper=conditionalUpsertMapper&condition=activeProductsCondition"/>
</route>
</routes>
Using integrateMapper in a Complete Route
mappers/integrate-product-mapper.xml:
<mappers>
<integrateMapper id="integrateProductMapper" includeUnmappedProperties="false">
<body in="sku"/>
<body in="name" out="label"/>
<body in="price" out="attribute1" converter="stringToNumber"/>
</integrateMapper>
</mappers>
routes/csv-to-product-upsert.xml:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="csvToProductUpsert">
<from uri="file:{{inbound.path}}/products?move=.done"/>
<to uri="pfx-csv:unmarshal?delimiter=,"/>
<split>
<simple>${body}</simple>
<to uri="pfx-api:integrate?objectType=P&mapper=integrateProductMapper"/>
</split>
<log message="Product upsert complete"/>
</route>
</routes>
How It Works
-
<integrateMapper>wraps field mappings just like<loadMapper>, but the mapped output is sent to thepfx-api:integrateendpoint which performs upsert logic. -
Business keys (typically
skufor Products,customerIdfor Customers) are used by Pricefx to find existing records. If found, the record is updated; if not, a new record is created. -
includeUnmappedProperties="false"ensures only explicitly mapped fields are sent. This prevents accidentally overwriting fields with stale or null data. -
includeNulls="true"explicitly sends null values, which clears those fields in Pricefx. Default isfalse, meaning null fields are omitted from the upsert payload. -
Condition filters on the integrate endpoint add server-side criteria to control which existing records are considered for matching.
Common Pitfalls
-
Missing business key: If you forget to map the business key field (e.g.,
sku), every record will be treated as a new insert, creating duplicates. -
includeNullsdefault: By default,includeNullsisfalse. If you want to clear a field value in Pricefx, you must explicitly setincludeNulls="true". -
includeUnmappedPropertiesdefault: By default, this istrue, meaning ALL source fields pass through to the output. For upsert operations, always set it tofalseto avoid sending unexpected fields. -
Condition filter scope: The condition filter narrows which existing records are matched. It does not filter the incoming data -- for that, use route-level filtering or a Camel
<filter>step. -
loadMapper vs integrateMapper: Using
<loadMapper>withpfx-api:integratewill not work as expected. Always pair<integrateMapper>with integrate endpoints. -
Custom converters: Never define
<beans:bean>elements inline inside a mapper file. Standard converters (stringToDecimal,stringToNumber, etc.) need no bean definition. Custom ones go inbeans/.