Is there a working example which sends and receives SQS messages using JMS?

I am evaluating the inclusion of LocalStack in our development process.
To that effort I need to show that we can use JMS in a Spring application to send and receive messages to SQS.
So far I have been unsuccessful at finding or writing a working example.
We are using Spring 6 and Spring Boot 3.

Can someone point me to a working example?

Thanks

Hey Paul @greenpm-fis!

Here’s a super minimal send/receive in a single application using JMS and LocalStack SQS. LocalStack needs to special start configuration, SQS should work out of the box with localstack start.

Here’s the Java code. You’ll notice the only custom part is where we create the AmaonzSQS client using the AwsClientBuilder, which connects to the LocalStack endpoint rather than AWS. Everything else is standard JMS and Amazon’s SQS binding to JMS.

package cloud.localstack;

import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper;
import com.amazon.sqs.javamessaging.ProviderConfiguration;
import com.amazon.sqs.javamessaging.SQSConnection;
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;

import javax.jms.*;


public class Main {

    public static AmazonSQS getLocalstackSqsClient() {
        return AmazonSQSClientBuilder.standard().withEndpointConfiguration(
                new AwsClientBuilder.EndpointConfiguration(
                        "http://localhost.localstack.cloud:4566",
                        "us-east-1"
                )
        ).build();
    }

    public static void main(String[] args) throws Exception {
        // Create a new connection factory with all defaults (credentials and region) set automatically
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
                new ProviderConfiguration(),
                getLocalstackSqsClient()
        );

        // Create the connection.
        SQSConnection connection = connectionFactory.createConnection("test", "test");
        // Get the wrapped client
        AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient();
        // Create an SQS queue named MyQueue, if it doesn't already exist
        if (!client.queueExists("MyQueue")) {
            client.createQueue("MyQueue");
        }

        // javax.jms part
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // Create a queue identity and specify the queue name to the session
        Queue queue = session.createQueue("MyQueue");
        // Create the nontransacted session with AUTO_ACKNOWLEDGE mode
        MessageProducer producer = session.createProducer(queue);
        // Create the text message
        TextMessage message = session.createTextMessage("Hello World!");
        // Send the message
        producer.send(message);
        System.out.println("JMS Message " + message.getJMSMessageID());

        // Create a consumer for the 'MyQueue'
        MessageConsumer consumer = session.createConsumer(queue);
        // Start receiving incoming messages
        connection.start();
        // Receive a message from 'MyQueue' and wait up to 1 second
        Message receivedMessage = consumer.receive(1000);
        // Cast the received message as TextMessage and display the text
        if (receivedMessage != null) {
            System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
        }

        // exit
        session.close();
        connection.close();

        System.exit(0);
    }
}

Let us know if you have any issues specific to LocalStack!

Thanks Thomas. This was greatly appreciated.
The example needed only minor changes for Java 17.

import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper;
import com.amazon.sqs.javamessaging.ProviderConfiguration;
import com.amazon.sqs.javamessaging.SQSConnection;
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;

import java.net.URI;
import java.util.concurrent.CompletableFuture;

import jakarta.jms.Message;
import jakarta.jms.MessageConsumer;
import jakarta.jms.MessageProducer;
import jakarta.jms.Queue;
import jakarta.jms.Session;
import jakarta.jms.TextMessage;
import software.amazon.awssdk.endpoints.Endpoint;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.endpoints.SqsEndpointProvider;

public class Main {
    public static final String ENDPOINT = "http://localhost.localstack.cloud:4566";
    public static final Region REGION = Region.US_EAST_1;
    public static final String QUEUE_NAME = "MyQueue";
/*
    public static AmazonSQS getLocalstackSqsClient() {
        return AmazonSQSClientBuilder.standard().withEndpointConfiguration(
            new AwsClientBuilder.EndpointConfiguration(
                ENDPOINT,
                REGION.id()
            )
        ).build();
    }
*/
    public static SqsEndpointProvider getEndpointProvider() {
        return endpointParams ->
            CompletableFuture.completedFuture(
                Endpoint.builder()
                    .url(URI.create(ENDPOINT))
                    .build());
    }

    public static SqsClient getLocalstackSqsClientForJava17() {
        return
            SqsClient.builder()
                .region(REGION)
                .endpointProvider(getEndpointProvider())
                .build();
    }

    public static void main(String[] args) throws Exception {

        // Create a new connection factory with all defaults (credentials and region) set automatically
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
            new ProviderConfiguration(),
            getLocalstackSqsClientForJava17()
        );
...
1 Like