Skip to main content

Transformer

A Transformer changes a message's payload or structure. It is the tool of choice when one route step's output type differs from the previous step's input type. Examples: parse a JSON envelope, base64-decode a binary payload, map a FIX message to a Kafka-friendly record.

PropertyValue
Java interfacecom.connamara.sdk.v1.adapter.components.Transformer
MethodMessage<?> transform(Message<?> message)
Pipeline slotAfter Conditions, before Processors.
Return contractA new Message<?> (use DerivedMessage.derive(...)) or the input message reference unchanged.
Side effectsDiscouraged. Transformers should be pure with respect to their input message; persistent side effects belong in a Processor.

Complete example

package com.example.myplugin;

import com.connamara.sdk.v1.adapter.components.Transformer;
import com.connamara.sdk.v1.common.component.ManifestResource;
import com.connamara.sdk.v1.common.message.DerivedMessage;
import com.connamara.sdk.v1.common.message.Message;

import java.util.Map;

@ManifestResource("""
{
"id": "uppercase-transformer",
"pluginId": "my-plugin",
"functionalType": "uppercase-transformer",
"displayName": "Uppercase Transformer",
"category": "TRANSFORMER",
"configuration": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Uppercase Settings",
"properties": {}
}
}
""")
public class UpperCaseTransformer implements Transformer {

public UpperCaseTransformer(Map<String, Object> config) {
// No configuration needed for this transformer.
}

@Override
public Message<?> transform(Message<?> message) {
Object payload = message.getPayload();
if (payload instanceof String text) {
return DerivedMessage.derive(message, text.toUpperCase(), Map.of());
}
return message;
}
}

Key rules

  • Headers are reused, not copied. The DerivedMessage.derive(...) wrapper references the source message's headers. Never build a fresh MessageHeaders map; doing so allocates and breaks the platform's zero-copy contract.
  • Return the input reference for pass-through. When a Transformer cannot apply (wrong payload type, feature toggle off), return the original message reference unchanged. Do not return a derived copy with no changes; the wrapper is wasted work.
  • No null. Transformers cannot drop messages. Returning null is a Processor-only behavior. If a Transformer needs to drop, restructure the route so a Processor follows.
  • Constructor argument. Every Transformer constructor takes Map<String, Object> populated from the Portal form, even when the configuration is empty.

Test pattern

@Test
@DisplayName("GIVEN a lowercase string payload WHEN transformed THEN payload is uppercase")
void transform_uppercasesString() {
UpperCaseTransformer transformer = new UpperCaseTransformer(Map.of());

Message<String> message = mock(Message.class);
when(message.getPayload()).thenReturn("hello world");
when(message.getHeaders()).thenReturn(new MessageHeaders(Collections.emptyMap()));

Message<?> result = transformer.transform(message);

assertEquals("HELLO WORLD", result.getPayload());
}

When to reach for a Transformer

NeedReach for
Convert payload type or wire format.Transformer.
Add a derived header without modifying the payload.Transformer if the header is a function of the payload; Processor if it depends on external state or has side effects.
Drop the message based on its content.Processor (Transformers cannot return null).
Decide whether the route should run at all.Condition, not Transformer.

See also