Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions spring-boot-modules/spring-boot-4/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: '3.8'

services:
activemq:
image: apache/activemq-artemis:2.37.0
container_name: activemq-artemis
ports:
- "61616:61616" # OpenWire (JMS)
- "8161:8161" # Web Console
environment:
- ARTEMIS_USER=admin
- ARTEMIS_PASSWORD=admin
25 changes: 25 additions & 0 deletions spring-boot-modules/spring-boot-4/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>activemq</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
Expand All @@ -77,6 +93,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.baeldung.spring.jms;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
class ArticleListener {

@Getter
private List<ArticlePublisher.Article> receivedArticles = new CopyOnWriteArrayList<>();

@JmsListener(destination = "articles-queue")
void onArticleReceived(ArticlePublisher.Article article) {
log.info("Received article: {}", article);
receivedArticles.add(article);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.baeldung.spring.jms;

import org.springframework.jms.core.JmsClient;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
class ArticlePublisher {

private final JmsClient jmsClient;

@SneakyThrows
// @EventListener(ApplicationReadyEvent.class)
// Uncomment the above line to enable automatic publishing on application startup, for local testing
void onApplicationReady() {
Thread.sleep(5_000);
publish("Understanding JMS in Spring Boot", "John Doe");
publish("A Guide to Spring JMS", "Jane Smith");
}


public void publish(String title, String author) {
var article = new Article(title, author);
log.info("Publishing article: {}", article);

jmsClient.destination("articles-queue")
.send(article);
}

record Article(String title, String author) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.baeldung.spring.jms;

import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Session;
import jakarta.jms.TextMessage;

import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.json.JsonMapper;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

@Component
@RequiredArgsConstructor
public class JsonMessageConverter implements MessageConverter {

private final JsonMapper jsonMapper = JsonMapper.builder()
.build();

@SneakyThrows
@Override
public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {

var json = jsonMapper.writeValueAsString(object);
var msg = session.createTextMessage(json);
msg.setStringProperty("_type", object.getClass().getName());
return msg;
}

@Override
@SneakyThrows
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {

if (message instanceof TextMessage msg ) {
var clazz = Class.forName(msg.getStringProperty("_type"));
return jsonMapper.readValue(msg.getText(), clazz);
}
throw new MessageConversionException("Message is not of type TextMessage");
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
application.rest.services.christmasJoy.baseUrl: https://christmasjoy.dev/api

spring:
application:
name: baeldung-spring-boot-4

artemis:
mode: native
broker-url: tcp://localhost:61616
user: admin
password: admin
jms:
template:
default-destination: demo-queue

logging:
level:
org.springframework.jms: DEBUG
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.baeldung.spring.jms;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.testcontainers.activemq.ArtemisContainer;
import org.testcontainers.utility.DockerImageName;

import com.baeldung.spring.SampleApplication;
import com.baeldung.spring.jms.ArticlePublisher.Article;

@SpringBootTest(classes = {SampleApplication.class, ArticleListenerLiveTest.TestConfig.class})
class ArticleListenerLiveTest {

@Autowired
ArticlePublisher articlePublisher;

@Autowired
ArticleListener articleListener;

@Test
void shouldReceivePublishedArticle() {
articlePublisher.publish("Foo", "John Doe");
articlePublisher.publish("Bar", "John Doe");

await().untilAsserted(() -> assertThat(articleListener.getReceivedArticles()).map(
Article::title).containsExactly("Foo", "Bar"));
}

@Configuration
static class TestConfig {
@Bean
@ServiceConnection
public ArtemisContainer activeMQ() {
return new ArtemisContainer(
DockerImageName.parse("apache/activemq-artemis:2.37.0"));
}
}
}