Skip to content

Payload Serialization

Records are serialized before storage and deserialized during processing. The library provides flexible serialization through the OutboxPayloadSerializer interface.

Jackson Module (Default)

The namastack-outbox-jackson module provides default JSON serialization using Jackson 3.x:

dependencies {
  implementation("io.namastack:namastack-outbox-starter-jpa:1.0.0")  # Includes Jackson by default
}

Supported Features:

  • JSON serialization/deserialization
  • Custom Jackson modules and mixins
  • Standard Jackson configuration via spring.jackson.* properties

Example Jackson Configuration:

spring:
  jackson:
    default-property-inclusion: NON_NULL
    serialization:
      write-dates-as-timestamps: false
      indent-output: true
    deserialization:
      fail-on-unknown-properties: false

OutboxPayloadSerializer Interface

Implement custom serializers for alternative formats (Protobuf, Avro, XML, etc.):

interface OutboxPayloadSerializer {
    fun serialize(payload: Any): String
    fun <T> deserialize(data: String, targetType: Class<T>): T
}
public interface OutboxPayloadSerializer {
    String serialize(Object payload);
    <T> T deserialize(String data, Class<T> targetType);
}

Custom Serializer Implementation

@Configuration
class OutboxSerializationConfig {
    @Bean
    fun protobufSerializer(): OutboxPayloadSerializer {
        return object : OutboxPayloadSerializer {
            override fun serialize(payload: Any): String {
                // Implement Protobuf serialization
                require(payload is Message) { "Payload must be Protobuf Message" }
                return Base64.encoder.encodeToString(payload.toByteArray())
            }

            override fun <T> deserialize(data: String, targetType: Class<T>): T {
                // Implement Protobuf deserialization
                val bytes = Base64.decoder.decode(data)
                val method = targetType.getMethod("parseFrom", ByteArray::class.java)
                @Suppress("UNCHECKED_CAST")
                return method.invoke(null, bytes) as T
            }
        }
    }
}
@Configuration
public class OutboxSerializationConfig {
    @Bean
    public OutboxPayloadSerializer protobufSerializer() {
        return new OutboxPayloadSerializer() {
            @Override
            public String serialize(Object payload) {
                if (!(payload instanceof Message)) {
                    throw new IllegalArgumentException("Payload must be Protobuf Message");
                }
                byte[] bytes = ((Message) payload).toByteArray();
                return Base64.getEncoder().encodeToString(bytes);
            }

            @Override
            public <T> T deserialize(String data, Class<T> targetType) {
                try {
                    byte[] bytes = Base64.getDecoder().decode(data);
                    java.lang.reflect.Method method = targetType.getMethod("parseFrom", byte[].class);
                    return (T) method.invoke(null, bytes);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }
}

Important: When you provide a custom serializer as a Spring bean, it automatically replaces the default Jackson serializer.