Spring Boot adapter

com.babelqueue:babelqueue-spring plugs the Java core into Spring AMQP. Its auto-configuration registers a MessageConverter that encodes/decodes the canonical envelope, so Boot wires it into both the RabbitTemplate (producing) and your @RabbitListener containers (consuming) — no manual setup.

Install

Maven:

<dependency>
    <groupId>com.babelqueue</groupId>
    <artifactId>babelqueue-spring</artifactId>
    <version>1.0.0</version>
</dependency>

Gradle:

implementation("com.babelqueue:babelqueue-spring:1.0.0")
implementation("org.springframework.boot:spring-boot-starter-amqp")

Requirements: Spring Boot 3, Java 17+, RabbitMQ. The core (babelqueue-core) comes transitively.

Configuration

# application.yaml
babelqueue:
  default-queue: orders   # written to meta.queue; used when no queue is given

Auto-configuration exposes one MessageConverter bean (BabelQueueMessageConverter) and a BabelQueuePublisher. Both back off if your app defines its own. Boot’s RabbitMQ auto-config injects the single converter into the RabbitTemplate and the default listener container factory.

Produce

Inject BabelQueuePublisher. Its publish(...) methods return the message meta.id:

import com.babelqueue.spring.BabelQueuePublisher;
import java.util.Map;
import org.springframework.stereotype.Service;

@Service
class Orders {
    private final BabelQueuePublisher babelQueue;

    Orders(BabelQueuePublisher babelQueue) {
        this.babelQueue = babelQueue;
    }

    void create() {
        babelQueue.publish("urn:babel:orders:created", Map.of("order_id", 1042L), "orders");
    }
}

Available overloads: publish(urn, data), publish(urn, data, queue), publish(urn, data, queue, traceId), and — for a typed message implementing com.babelqueue.PolyglotMessagepublish(message) / publish(message, queue).

Each message carries the contract AMQP properties: type = URN, correlationId = trace_id, messageId = meta.id, plus x-attempts / x-schema-version / x-source-lang headers, application/json and persistent delivery.

Consume

A normal @RabbitListener receives a decoded core Envelope; route by URN with EnvelopeCodec.urn(...):

import com.babelqueue.Envelope;
import com.babelqueue.EnvelopeCodec;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
class OrderListener {
    @RabbitListener(queues = "orders")
    void onMessage(Envelope envelope) {
        if ("urn:babel:orders:created".equals(EnvelopeCodec.urn(envelope))) {
            var orderId = envelope.data().get("order_id");
            // ... use envelope.traceId(), envelope.data()
        }
    }
}

Non-conformant messages (missing URN, unsupported meta.schema_version, blank trace_id, or missing data) are rejected by the converter — route them to a dead-letter exchange the usual Spring AMQP way.

Because the wire format is the canonical envelope, a message your Spring app consumes may have been produced by any BabelQueue SDK, and vice-versa.