SAP CPI Groovy Scripting: Common Patterns and Snippets
Practical Groovy script patterns for SAP Cloud Integration (CPI): reading/writing message properties, header manipulation, custom XML/JSON transformation, and error handling.
Published June 25, 2026
Advertisement
SAP CPI Groovy Scripting: Common Patterns and Snippets
Standard-defined message mapping steps in SAP Cloud Integration (CPI) cover most cases, but the moment you need conditional logic, custom validation, or a transformation not expressible in a graphical mapping, you reach for a Groovy Script step. Here are the patterns that come up constantly.
Reading and Writing the Message Body
import com.sap.gateway.ip.core.customdev.util.Message
Message processData(Message message) {
def body = message.getBody(String) as String
// ... transform body ...
message.setBody(body)
return message
}
Working with Headers and Properties
Headers and exchange properties are the two ways data travels alongside the payload through an iFlow:
Message processData(Message message) {
def map = message.getProperties()
def orderId = map.get("OrderId")
// Set a header for a downstream adapter (e.g. a dynamic HTTP path)
message.setHeader("CamelHttpPath", "/orders/" + orderId)
// Set a property to pass data to a later step without exposing it externally
message.setProperty("InternalRetryCount", "0")
return message
}
Rule of thumb: use properties for data that should stay internal to the iFlow, and headers only when a downstream adapter or a specific step needs to read them (headers can leak to the receiver system depending on the adapter).
Custom JSON to XML (or Vice Versa) When Mapping Falls Short
import groovy.json.JsonSlurper
import groovy.xml.MarkupBuilder
Message processData(Message message) {
def json = new JsonSlurper().parseText(message.getBody(String) as String)
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.Order {
OrderId(json.orderId)
Customer(json.customer.name)
}
message.setBody(writer.toString())
return message
}
Error Handling Inside a Script Step
Throwing a plain exception aborts the iFlow with a generic message. Wrap it to surface something useful in Message Processing Logs:
Message processData(Message message) {
try {
// risky transformation
} catch (Exception e) {
throw new RuntimeException("Failed to transform payload: " + e.getMessage(), e)
}
return message
}
Common Pitfall: Script State
Don't rely on static/global variables for state between message executions β CPI reuses worker threads, and a script step is not guaranteed a fresh instance per message. Keep all state on the Message object (body, headers, properties) instead.
If you're scaffolding a new integration pattern from scratch, our CPI iFlow Template Generator produces sender/receiver adapter configuration plus a Groovy stub to start from, and the JSON Formatter is handy for inspecting payloads captured from Message Processing Logs before you write the transformation.
Topics: