From bb73d05dbdf5d20ac22381a6de13f6b28f84cb63 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 7 Sep 2024 02:58:43 +0700 Subject: [PATCH 001/111] GH-2809: Fix MultiRabbitListenerAnnotationBeanPostProcessor Fixes: #2809 Issue link: https://github.com/spring-projects/spring-amqp/issues/2809 * Add `BeanNameAware` to the `RabbitListenerContainerFactory` and `getBeanName()` * Use `getBeanName()` from `RabbitListenerContainerFactory` and `RabbitAdmin` in the `MultiRabbitListenerAnnotationBeanPostProcessor.resolveMultiRabbitAdminName()` --- ...itListenerAnnotationBeanPostProcessor.java | 35 +++++++++++++++---- ...itListenerAnnotationBeanPostProcessor.java | 5 +-- .../BaseRabbitListenerContainerFactory.java | 13 +++++++ .../RabbitListenerContainerFactory.java | 21 +++++++++-- .../AbstractRabbitAnnotationDrivenTests.java | 7 ++++ .../RabbitListenerContainerTestFactory.java | 13 ++++++- 6 files changed, 82 insertions(+), 12 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/MultiRabbitListenerAnnotationBeanPostProcessor.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/MultiRabbitListenerAnnotationBeanPostProcessor.java index 939bd6b583..0764691e1e 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/MultiRabbitListenerAnnotationBeanPostProcessor.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/MultiRabbitListenerAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,8 @@ import org.springframework.amqp.core.Declarable; import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; import org.springframework.util.StringUtils; /** @@ -35,6 +37,7 @@ * configuration, preventing the server from automatic binding non-related structures. * * @author Wander Costa + * @author Ngoc Nhan * * @since 2.3 */ @@ -70,14 +73,32 @@ private RabbitListener proxyIfAdminNotPresent(final RabbitListener rabbitListene * @return The name of the RabbitAdmin bean. */ protected String resolveMultiRabbitAdminName(RabbitListener rabbitListener) { - String admin = super.resolveExpressionAsString(rabbitListener.admin(), "admin"); - if (!StringUtils.hasText(admin) && StringUtils.hasText(rabbitListener.containerFactory())) { - admin = rabbitListener.containerFactory() + RabbitListenerConfigUtils.MULTI_RABBIT_ADMIN_SUFFIX; + + var admin = rabbitListener.admin(); + if (StringUtils.hasText(admin)) { + + var resolved = super.resolveExpression(admin); + if (resolved instanceof RabbitAdmin rabbitAdmin) { + + return rabbitAdmin.getBeanName(); + } + + return super.resolveExpressionAsString(admin, "admin"); } - if (!StringUtils.hasText(admin)) { - admin = RabbitListenerConfigUtils.RABBIT_ADMIN_BEAN_NAME; + + var containerFactory = rabbitListener.containerFactory(); + if (StringUtils.hasText(containerFactory)) { + + var resolved = super.resolveExpression(containerFactory); + if (resolved instanceof RabbitListenerContainerFactory rlcf) { + + return rlcf.getBeanName() + RabbitListenerConfigUtils.MULTI_RABBIT_ADMIN_SUFFIX; + } + + return containerFactory + RabbitListenerConfigUtils.MULTI_RABBIT_ADMIN_SUFFIX; } - return admin; + + return RabbitListenerConfigUtils.RABBIT_ADMIN_BEAN_NAME; } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java index ffdd652657..6946bb28e8 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,6 +119,7 @@ * @author Gary Russell * @author Alex Panchenko * @author Artem Bilan + * @author Ngoc Nhan * * @since 1.4 * @@ -961,7 +962,7 @@ else if (resolved instanceof Integer) { } } - private Object resolveExpression(String value) { + protected Object resolveExpression(String value) { String resolvedValue = resolve(value); return this.resolver.evaluate(resolvedValue, this.expressionContext); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/BaseRabbitListenerContainerFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/BaseRabbitListenerContainerFactory.java index 5a1fab024a..6363bbe18c 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/BaseRabbitListenerContainerFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/BaseRabbitListenerContainerFactory.java @@ -43,6 +43,7 @@ * @param the container type that the factory creates. * * @author Gary Russell + * @author Ngoc Nhan * @since 2.4 * */ @@ -67,6 +68,8 @@ public abstract class BaseRabbitListenerContainerFactory the container type. * @author Stephane Nicoll * @author Gary Russell + * @author Ngoc Nhan * @since 1.4 * @see RabbitListenerEndpoint */ @FunctionalInterface -public interface RabbitListenerContainerFactory { +public interface RabbitListenerContainerFactory extends BeanNameAware { /** * Create a {@link MessageListenerContainer} for the given @@ -48,4 +50,19 @@ default C createListenerContainer() { return createListenerContainer(null); } + @Override + default void setBeanName(String name) { + + } + + /** + * Return a bean name of the component or null if not a bean. + * @return the bean name. + * @since 3.2 + */ + @Nullable + default String getBeanName() { + return null; + } + } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/AbstractRabbitAnnotationDrivenTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/AbstractRabbitAnnotationDrivenTests.java index 271731d2af..bdfb6abbca 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/AbstractRabbitAnnotationDrivenTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/AbstractRabbitAnnotationDrivenTests.java @@ -48,6 +48,7 @@ * * @author Stephane Nicoll * @author Gary Russell + * @author Ngoc Nhan */ public abstract class AbstractRabbitAnnotationDrivenTests { @@ -87,7 +88,9 @@ public void testSampleConfiguration(ApplicationContext context, int expectedDefa context.getBean("rabbitListenerContainerFactory", RabbitListenerContainerTestFactory.class); RabbitListenerContainerTestFactory simpleFactory = context.getBean("simpleFactory", RabbitListenerContainerTestFactory.class); + assertThat(defaultFactory.getBeanName()).isEqualTo("rabbitListenerContainerFactory"); assertThat(defaultFactory.getListenerContainers()).hasSize(expectedDefaultContainers); + assertThat(simpleFactory.getBeanName()).isEqualTo("simpleFactory"); assertThat(simpleFactory.getListenerContainers()).hasSize(1); Map queues = context .getBeansOfType(org.springframework.amqp.core.Queue.class); @@ -129,6 +132,7 @@ private void checkAdmin(Collection admins) { public void testFullConfiguration(ApplicationContext context) { RabbitListenerContainerTestFactory simpleFactory = context.getBean("simpleFactory", RabbitListenerContainerTestFactory.class); + assertThat(simpleFactory.getBeanName()).isEqualTo("simpleFactory"); assertThat(simpleFactory.getListenerContainers()).hasSize(1); MethodRabbitListenerEndpoint endpoint = (MethodRabbitListenerEndpoint) simpleFactory.getListenerContainers().get(0).getEndpoint(); @@ -168,7 +172,9 @@ public void testCustomConfiguration(ApplicationContext context) { context.getBean("rabbitListenerContainerFactory", RabbitListenerContainerTestFactory.class); RabbitListenerContainerTestFactory customFactory = context.getBean("customFactory", RabbitListenerContainerTestFactory.class); + assertThat(defaultFactory.getBeanName()).isEqualTo("rabbitListenerContainerFactory"); assertThat(defaultFactory.getListenerContainers()).hasSize(1); + assertThat(customFactory.getBeanName()).isEqualTo("customFactory"); assertThat(customFactory.getListenerContainers()).hasSize(1); RabbitListenerEndpoint endpoint = defaultFactory.getListenerContainers().get(0).getEndpoint(); assertThat(endpoint.getClass()).as("Wrong endpoint type").isEqualTo(SimpleRabbitListenerEndpoint.class); @@ -191,6 +197,7 @@ public void testCustomConfiguration(ApplicationContext context) { public void testExplicitContainerFactoryConfiguration(ApplicationContext context) { RabbitListenerContainerTestFactory defaultFactory = context.getBean("simpleFactory", RabbitListenerContainerTestFactory.class); + assertThat(defaultFactory.getBeanName()).isEqualTo("simpleFactory"); assertThat(defaultFactory.getListenerContainers()).hasSize(1); } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/config/RabbitListenerContainerTestFactory.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/config/RabbitListenerContainerTestFactory.java index fa592274fb..9e68785e27 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/config/RabbitListenerContainerTestFactory.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/config/RabbitListenerContainerTestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,8 @@ public class RabbitListenerContainerTestFactory implements RabbitListenerContain private final Map listenerContainers = new LinkedHashMap(); + private String beanName; + public List getListenerContainers() { return new ArrayList(this.listenerContainers.values()); } @@ -63,4 +65,13 @@ public MessageListenerTestContainer createListenerContainer(RabbitListenerEndpoi return container; } + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + public String getBeanName() { + return this.beanName; + } + } From 8e9c9e40363ad85d02d4ca84ae431b4a1e0adbae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:57:20 +0000 Subject: [PATCH 002/111] Bump com.github.spotbugs in the development-dependencies group (#2812) Bumps the development-dependencies group with 1 update: com.github.spotbugs. Updates `com.github.spotbugs` from 6.0.21 to 6.0.22 --- updated-dependencies: - dependency-name: com.github.spotbugs dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b7eb6a7dc7..740da931ea 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' - id 'com.github.spotbugs' version '6.0.21' + id 'com.github.spotbugs' version '6.0.22' id 'io.freefair.aggregate-javadoc' version '8.6' } From 104a6e1fad6860812e97be17eba83c4e6c164759 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:59:16 +0000 Subject: [PATCH 003/111] Bump ch.qos.logback:logback-classic from 1.5.7 to 1.5.8 (#2813) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.7 to 1.5.8. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.7...v_1.5.8) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 740da931ea..fdcb43990a 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ ext { junitJupiterVersion = '5.11.0' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.23.1' - logbackVersion = '1.5.7' + logbackVersion = '1.5.8' lz4Version = '1.8.0' micrometerDocsVersion = '1.0.3' micrometerVersion = '1.14.0-SNAPSHOT' From c5bd5424e37dd8867b0c79530f59477966fa0077 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 02:26:02 +0000 Subject: [PATCH 004/111] Bump the development-dependencies group with 2 updates (#2817) Bumps the development-dependencies group with 2 updates: [io.micrometer:micrometer-docs-generator](https://github.com/micrometer-metrics/micrometer-docs-generator) and [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions). Updates `io.micrometer:micrometer-docs-generator` from 1.0.3 to 1.0.4 - [Release notes](https://github.com/micrometer-metrics/micrometer-docs-generator/releases) - [Commits](https://github.com/micrometer-metrics/micrometer-docs-generator/compare/v1.0.3...v1.0.4) Updates `io.spring.develocity.conventions` from 0.0.20 to 0.0.21 - [Release notes](https://github.com/spring-io/develocity-conventions/releases) - [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.20...v0.0.21) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-docs-generator dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: io.spring.develocity.conventions dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- settings.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index fdcb43990a..da05b55a2e 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ ext { log4jVersion = '2.23.1' logbackVersion = '1.5.8' lz4Version = '1.8.0' - micrometerDocsVersion = '1.0.3' + micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-SNAPSHOT' mockitoVersion = '5.12.0' diff --git a/settings.gradle b/settings.gradle index 4e1e2619ab..5c20e31b03 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,7 +7,7 @@ pluginManagement { plugins { id 'com.gradle.develocity' version '3.17.6' - id 'io.spring.develocity.conventions' version '0.0.20' + id 'io.spring.develocity.conventions' version '0.0.21' } rootProject.name = 'spring-amqp-dist' From 762d6a6914d26559856935172adfbe3b7f2265e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 02:26:10 +0000 Subject: [PATCH 005/111] Bump org.springframework.retry:spring-retry from 2.0.8 to 2.0.9 (#2820) Bumps [org.springframework.retry:spring-retry](https://github.com/spring-projects/spring-retry) from 2.0.8 to 2.0.9. - [Release notes](https://github.com/spring-projects/spring-retry/releases) - [Commits](https://github.com/spring-projects/spring-retry/compare/v2.0.8...v2.0.9) --- updated-dependencies: - dependency-name: org.springframework.retry:spring-retry dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index da05b55a2e..73cf6e25f1 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ ext { reactorVersion = '2024.0.0-SNAPSHOT' snappyVersion = '1.1.10.6' springDataVersion = '2024.0.3' - springRetryVersion = '2.0.8' + springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.19.8' zstdJniVersion = '1.5.6-5' From d603111d79191aa50529c811fcb1c48c8ae2e017 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 02:29:40 +0000 Subject: [PATCH 006/111] Bump org.springframework.data:spring-data-bom from 2024.0.3 to 2024.0.4 (#2819) Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.3 to 2024.0.4. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.3...2024.0.4) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 73cf6e25f1..ca35fd8932 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ ext { rabbitmqVersion = '5.21.0' reactorVersion = '2024.0.0-SNAPSHOT' snappyVersion = '1.1.10.6' - springDataVersion = '2024.0.3' + springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.19.8' From 5db0ee250896d726730cfe1f5313b191a7335b30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 02:33:44 +0000 Subject: [PATCH 007/111] Bump org.xerial.snappy:snappy-java from 1.1.10.6 to 1.1.10.7 (#2818) Bumps [org.xerial.snappy:snappy-java](https://github.com/xerial/snappy-java) from 1.1.10.6 to 1.1.10.7. - [Release notes](https://github.com/xerial/snappy-java/releases) - [Commits](https://github.com/xerial/snappy-java/compare/v1.1.10.6...v1.1.10.7) --- updated-dependencies: - dependency-name: org.xerial.snappy:snappy-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ca35fd8932..fddd060b39 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ ext { rabbitmqStreamVersion = '0.15.0' rabbitmqVersion = '5.21.0' reactorVersion = '2024.0.0-SNAPSHOT' - snappyVersion = '1.1.10.6' + snappyVersion = '1.1.10.7' springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' From 7d1e696d7f80d934999a11136e7812acfecee9db Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 16 Sep 2024 22:09:40 +0700 Subject: [PATCH 008/111] Exchange/routingKey as independet props in the RabbitMessageSenderContext --- .../amqp/rabbit/core/RabbitTemplate.java | 3 +- .../RabbitMessageSenderContext.java | 47 ++++++++++++++++++- .../support/micrometer/ObservationTests.java | 13 +++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java index dc33e807d8..5d2894c96c 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java @@ -159,6 +159,7 @@ * @author Mohammad Hewedy * @author Alexey Platonov * @author Leonardo Ferreira + * @author Ngoc Nhan * * @since 1.0 */ @@ -2486,7 +2487,7 @@ protected void observeTheSend(Channel channel, Message message, boolean mandator ObservationRegistry registry = getObservationRegistry(); Observation observation = RabbitTemplateObservation.TEMPLATE_OBSERVATION.observation(this.observationConvention, DefaultRabbitTemplateObservationConvention.INSTANCE, - () -> new RabbitMessageSenderContext(message, this.beanName, exch + "/" + rKey), registry); + () -> new RabbitMessageSenderContext(message, this.beanName, exch, rKey), registry); observation.observe(() -> sendToRabbit(channel, exch, rKey, mandatory, message)); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitMessageSenderContext.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitMessageSenderContext.java index e327f6ebc6..b7994ad645 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitMessageSenderContext.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitMessageSenderContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ * {@link SenderContext} for {@link Message}s. * * @author Gary Russell + * @author Ngoc Nhan * @since 3.0 * */ @@ -33,14 +34,40 @@ public class RabbitMessageSenderContext extends SenderContext { private final String destination; + private final String exchange; + + private final String routingKey; + + @Deprecated(since = "3.2") public RabbitMessageSenderContext(Message message, String beanName, String destination) { super((carrier, key, value) -> message.getMessageProperties().setHeader(key, value)); setCarrier(message); this.beanName = beanName; + this.exchange = null; + this.routingKey = null; this.destination = destination; setRemoteServiceName("RabbitMQ"); } + + /** + * Create an instance {@code RabbitMessageSenderContext}. + * @param message a message to send + * @param beanName the bean name + * @param exchange the name of the exchange + * @param routingKey the routing key + * @since 3.2 + */ + public RabbitMessageSenderContext(Message message, String beanName, String exchange, String routingKey) { + super((carrier, key, value) -> message.getMessageProperties().setHeader(key, value)); + setCarrier(message); + this.beanName = beanName; + this.exchange = exchange; + this.routingKey = routingKey; + this.destination = exchange + "/" + routingKey; + setRemoteServiceName("RabbitMQ"); + } + public String getBeanName() { return this.beanName; } @@ -53,4 +80,22 @@ public String getDestination() { return this.destination; } + /** + * Return the exchange. + * @return the exchange. + * @since 3.2 + */ + public String getExchange() { + return this.exchange; + } + + /** + * Return the routingKey. + * @return the routingKey. + * @since 3.2 + */ + public String getRoutingKey() { + return this.routingKey; + } + } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java index e1787df31f..4c0b6fa056 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,6 +66,7 @@ /** * @author Gary Russell + * @author Ngoc Nhan * @since 3.0 * */ @@ -110,7 +111,9 @@ void endToEnd(@Autowired Listener listener, @Autowired RabbitTemplate template, @Override public KeyValues getLowCardinalityKeyValues(RabbitMessageSenderContext context) { - return super.getLowCardinalityKeyValues(context).and("foo", "bar"); + return super.getLowCardinalityKeyValues(context).and("foo", "bar") + .and("messaging.destination.name", context.getExchange()) + .and("messaging.rabbitmq.destination.routing_key", context.getRoutingKey()); } }); @@ -135,6 +138,8 @@ public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context span = spans.poll(); assertThat(span.getTags()).containsEntry("spring.rabbit.template.name", "template"); assertThat(span.getTags()).containsEntry("foo", "bar"); + assertThat(span.getTags()).containsEntry("messaging.destination.name", ""); + assertThat(span.getTags()).containsEntry("messaging.rabbitmq.destination.routing_key", "observation.testQ1"); assertThat(span.getName()).isEqualTo("/observation.testQ1 send"); await().until(() -> spans.peekFirst().getTags().size() == 4); span = spans.poll(); @@ -142,10 +147,12 @@ public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context .containsAllEntriesOf(Map.of("spring.rabbit.listener.id", "obs1", "foo", "some foo value", "bar", "some bar value", "baz", "qux")); assertThat(span.getName()).isEqualTo("observation.testQ1 receive"); - await().until(() -> spans.peekFirst().getTags().size() == 2); + await().until(() -> spans.peekFirst().getTags().size() == 4); span = spans.poll(); assertThat(span.getTags()).containsEntry("spring.rabbit.template.name", "template"); assertThat(span.getTags()).containsEntry("foo", "bar"); + assertThat(span.getTags()).containsEntry("messaging.destination.name", ""); + assertThat(span.getTags()).containsEntry("messaging.rabbitmq.destination.routing_key", "observation.testQ2"); assertThat(span.getName()).isEqualTo("/observation.testQ2 send"); await().until(() -> spans.peekFirst().getTags().size() == 3); span = spans.poll(); From 2ebc7ef1234d5a6eced160bb132f392fbe84f92a Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 16 Sep 2024 23:39:12 +0700 Subject: [PATCH 009/111] GH-2815: Fix `RabbitAdmin` for static `Declarables Fixes: #2815 Issue link: https://github.com/spring-projects/spring-amqp/issues/2815 When rabbitmq resets, `RabbitAdmin#initialize` calls `redeclareManualDeclarables()` first, before it continues with re-declaring statically configured declarations. This means that explicitly declared Bindings to statically declared Exchanges can never be restored, because the Exchange has to exist in order for the Binding declaration to succeed. * Call new `redeclareBeanDeclarables()` before `redeclareManualDeclarables()` **Auto-cherry-pick to `3.1.x`** --- .../org/springframework/amqp/rabbit/core/RabbitAdmin.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitAdmin.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitAdmin.java index b86dc8063a..b85df8fece 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitAdmin.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitAdmin.java @@ -81,6 +81,7 @@ * @author Gary Russell * @author Artem Bilan * @author Christian Tzolov + * @author Ngoc Nhan */ @ManagedResource(description = "Admin Tasks") public class RabbitAdmin implements AmqpAdmin, ApplicationContextAware, ApplicationEventPublisherAware, @@ -648,8 +649,14 @@ public void afterPropertiesSet() { @Override // NOSONAR complexity public void initialize() { + redeclareBeanDeclarables(); redeclareManualDeclarables(); + } + /** + * Process bean declarables. + */ + private void redeclareBeanDeclarables() { if (this.applicationContext == null) { this.logger.debug("no ApplicationContext has been set, cannot auto-declare Exchanges, Queues, and Bindings"); return; From c6dcc76ae9bbf35caaec5d2d6cefa19232e8be49 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 16 Sep 2024 23:56:13 +0700 Subject: [PATCH 010/111] Fix links in docs * Fix links in section Previous Releases * Declare some attributes represent document links --- src/reference/antora/antora.yml | 13 ++++++++++++- .../ROOT/pages/amqp/broker-configuration.adoc | 2 +- .../antora/modules/ROOT/pages/amqp/connections.adoc | 2 +- .../modules/ROOT/pages/amqp/listener-queues.adoc | 2 +- .../ROOT/pages/amqp/management-rest-api.adoc | 2 +- .../modules/ROOT/pages/amqp/message-converters.adoc | 2 +- .../async-annotation-driven/enable.adoc | 2 +- .../receiving-messages/micrometer-observation.adoc | 2 +- .../pages/amqp/receiving-messages/micrometer.adoc | 2 +- .../modules/ROOT/pages/amqp/request-reply.adoc | 4 ++-- ...-recovering-from-errors-and-broker-failures.adoc | 2 +- .../modules/ROOT/pages/amqp/sending-messages.adoc | 2 +- .../modules/ROOT/pages/amqp/transactions.adoc | 8 ++++---- .../antora/modules/ROOT/pages/appendix/native.adoc | 2 +- .../changes-in-1-3-since-1-2.adoc | 13 ++++++------- .../changes-in-1-4-since-1-3.adoc | 8 ++++---- .../changes-in-1-5-since-1-4.adoc | 6 +++--- .../changes-in-1-6-since-1-5.adoc | 4 ++-- .../changes-in-1-7-since-1-6.adoc | 2 +- .../changes-in-2-0-since-1-7.adoc | 4 ++-- .../changes-in-2-1-since-2-0.adoc | 2 +- .../changes-to-1-2-since-1-1.adoc | 2 +- .../modules/ROOT/pages/integration-reference.adoc | 2 +- .../antora/modules/ROOT/pages/logging.adoc | 2 +- .../antora/modules/ROOT/pages/sample-apps.adoc | 6 +++--- src/reference/antora/modules/ROOT/pages/stream.adoc | 8 ++++---- 26 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/reference/antora/antora.yml b/src/reference/antora/antora.yml index fc3041c337..f3ceb248f4 100644 --- a/src/reference/antora/antora.yml +++ b/src/reference/antora/antora.yml @@ -14,4 +14,15 @@ ext: asciidoc: attributes: attribute-missing: 'warn' - chomp: 'all' \ No newline at end of file + chomp: 'all' + spring-docs: 'https://docs.spring.io' + spring-framework-docs: '{spring-docs}/spring-framework/reference' + spring-integration-docs: '{spring-docs}/spring-integration/reference' + spring-amqp-java-docs: '{spring-docs}/spring-amqp/docs/current/api/org/springframework/amqp' + spring-framework-java-docs: '{spring-docs}/spring/docs/current/javadoc-api/org/springframework' + spring-retry-java-docs: '{spring-docs}/spring-retry/docs/api/current/' + # External projects URLs and related attributes + micrometer-docs: 'https://docs.micrometer.io' + micrometer-tracing-docs: '{micrometer-docs}/tracing/reference/' + micrometer-micrometer-docs: '{micrometer-docs}/micrometer/reference/' + rabbitmq-stream-docs: 'https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle' \ No newline at end of file diff --git a/src/reference/antora/modules/ROOT/pages/amqp/broker-configuration.adoc b/src/reference/antora/modules/ROOT/pages/amqp/broker-configuration.adoc index c983716a37..1dbf6ac314 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/broker-configuration.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/broker-configuration.adoc @@ -359,7 +359,7 @@ public Exchange exchange() { } ---- -See the Javadoc for https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/core/QueueBuilder.html[`org.springframework.amqp.core.QueueBuilder`] and https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/core/ExchangeBuilder.html[`org.springframework.amqp.core.ExchangeBuilder`] for more information. +See the Javadoc for {spring-amqp-java-docs}/core/QueueBuilder.html[`org.springframework.amqp.core.QueueBuilder`] and {spring-amqp-java-docs}/core/ExchangeBuilder.html[`org.springframework.amqp.core.ExchangeBuilder`] for more information. Starting with version 2.0, the `ExchangeBuilder` now creates durable exchanges by default, to be consistent with the simple constructors on the individual `AbstractExchange` classes. To make a non-durable exchange with the builder, use `.durable(false)` before invoking `.build()`. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc b/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc index 42a4b0a199..da8bf568b8 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc @@ -483,7 +483,7 @@ public class MyService { ---- It is important to unbind the resource after use. -For more information, see the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.html[JavaDoc] for `AbstractRoutingConnectionFactory`. +For more information, see the {spring-amqp-java-docs}/rabbit/connection/AbstractRoutingConnectionFactory.html[JavaDoc] for `AbstractRoutingConnectionFactory`. Starting with version 1.4, `RabbitTemplate` supports the SpEL `sendConnectionFactorySelectorExpression` and `receiveConnectionFactorySelectorExpression` properties, which are evaluated on each AMQP protocol interaction operation (`send`, `sendAndReceive`, `receive`, or `receiveAndReply`), resolving to a `lookupKey` value for the provided `AbstractRoutingConnectionFactory`. You can use bean references, such as `@vHostResolver.getVHost(#root)` in the expression. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/listener-queues.adoc b/src/reference/antora/modules/ROOT/pages/amqp/listener-queues.adoc index 03fe292c7a..ed6101ec5c 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/listener-queues.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/listener-queues.adoc @@ -8,7 +8,7 @@ Container can be initially configured to listen on zero queues. Queues can be added and removed at runtime. The `SimpleMessageListenerContainer` recycles (cancels and re-creates) all consumers when any pre-fetched messages have been processed. The `DirectMessageListenerContainer` creates/cancels individual consumer(s) for each queue without affecting consumers on other queues. -See the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/listener/AbstractMessageListenerContainer.html[Javadoc] for the `addQueues`, `addQueueNames`, `removeQueues` and `removeQueueNames` methods. +See the {spring-amqp-java-docs}/rabbit/listener/AbstractMessageListenerContainer.html[Javadoc] for the `addQueues`, `addQueueNames`, `removeQueues` and `removeQueueNames` methods. If not all queues are available, the container tries to passively declare (and consume from) the missing queues every 60 seconds. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc b/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc index 445b46c8a1..a693e1e36d 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc @@ -5,7 +5,7 @@ When the management plugin is enabled, the RabbitMQ server exposes a REST API to monitor and configure the broker. A https://github.com/rabbitmq/hop[Java Binding for the API] is now provided. The `com.rabbitmq.http.client.Client` is a standard, immediate, and, therefore, blocking API. -It is based on the https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#spring-web[Spring Web] module and its `RestTemplate` implementation. +It is based on the {spring-framework-docs}/web.html[Spring Web] module and its `RestTemplate` implementation. On the other hand, the `com.rabbitmq.http.client.ReactorNettyClient` is a reactive, non-blocking implementation based on the https://projectreactor.io/docs/netty/release/reference/docs/index.html[Reactor Netty] project. The hop dependency (`com.rabbitmq:http-client`) is now also `optional`. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/message-converters.adoc b/src/reference/antora/modules/ROOT/pages/amqp/message-converters.adoc index b828342c4b..c028af61bd 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/message-converters.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/message-converters.adoc @@ -356,7 +356,7 @@ It has been replaced by `AbstractJackson2MessageConverter`. Yet another option is the `MarshallingMessageConverter`. It delegates to the Spring OXM library's implementations of the `Marshaller` and `Unmarshaller` strategy interfaces. -You can read more about that library https://docs.spring.io/spring/docs/current/spring-framework-reference/html/oxm.html[here]. +You can read more about that library {spring-framework-docs}/data-access/oxm.html[here]. In terms of configuration, it is most common to provide only the constructor argument, since most implementations of `Marshaller` also implement `Unmarshaller`. The following example shows how to configure a `MarshallingMessageConverter`: diff --git a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/enable.adoc b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/enable.adoc index 71d39dc08b..422de556ef 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/enable.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/enable.adoc @@ -37,7 +37,7 @@ In this case, and ignoring the RabbitMQ infrastructure setup, the `processOrder` You can customize the listener container factory to use for each annotation, or you can configure an explicit default by implementing the `RabbitListenerConfigurer` interface. The default is required only if at least one endpoint is registered without a specific container factory. -See the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/annotation/RabbitListenerConfigurer.html[Javadoc] for full details and examples. +See the {spring-amqp-java-docs}/rabbit/annotation/RabbitListenerConfigurer.html[Javadoc] for full details and examples. The container factories provide methods for adding `MessagePostProcessor` instances that are applied after receiving messages (before invoking the listener) and before sending replies. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer-observation.adoc b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer-observation.adoc index 7d30d09065..bbd1c340ee 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer-observation.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer-observation.adoc @@ -7,7 +7,7 @@ Using Micrometer for observation is now supported, since version 3.0, for the `R Set `observationEnabled` on each component to enable observation; this will disable xref:amqp/receiving-messages/micrometer.adoc[Micrometer Timers] because the timers will now be managed with each observation. When using annotated listeners, set `observationEnabled` on the container factory. -Refer to https://docs.micrometer.io/tracing/reference/[Micrometer Tracing] for more information. +Refer to {micrometer-tracing-docs}[Micrometer Tracing] for more information. To add tags to timers/traces, configure a custom `RabbitTemplateObservationConvention` or `RabbitListenerObservationConvention` to the template or listener container, respectively. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer.adoc b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer.adoc index efae24ebfb..bc581083ad 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/micrometer.adoc @@ -2,7 +2,7 @@ = Micrometer Integration :page-section-summary-toc: 1 -NOTE: This section documents the integration with https://docs.micrometer.io/micrometer/reference/[Micrometer]. +NOTE: This section documents the integration with {micrometer-micrometer-docs}[Micrometer]. For integration with Micrometer Observation, see xref:amqp/receiving-messages/micrometer-observation.adoc[Micrometer Observation]. Starting with version 2.2, the listener containers will automatically create and update Micrometer `Timer` s for the listener, if `Micrometer` is detected on the class path, and a single `MeterRegistry` is present in the application context (or exactly one is annotated `@Primary`, such as when using Spring Boot). diff --git a/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc b/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc index 57d515d987..2a17bb8350 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc @@ -6,11 +6,11 @@ Those methods are quite useful for request-reply scenarios, since they handle th Similar request-reply methods are also available where the `MessageConverter` is applied to both the request and reply. Those methods are named `convertSendAndReceive`. -See the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/core/AmqpTemplate.html[Javadoc of `AmqpTemplate`] for more detail. +See the {spring-amqp-java-docs}/core/AmqpTemplate.html[Javadoc of `AmqpTemplate`] for more detail. Starting with version 1.5.0, each of the `sendAndReceive` method variants has an overloaded version that takes `CorrelationData`. Together with a properly configured connection factory, this enables the receipt of publisher confirms for the send side of the operation. -See xref:amqp/template.adoc#template-confirms[Correlated Publisher Confirms and Returns] and the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/core/RabbitOperations.html[Javadoc for `RabbitOperations`] for more information. +See xref:amqp/template.adoc#template-confirms[Correlated Publisher Confirms and Returns] and the {spring-amqp-java-docs}/rabbit/core/RabbitOperations.html[Javadoc for `RabbitOperations`] for more information. Starting with version 2.0, there are variants of these methods (`convertSendAndReceiveAsType`) that take an additional `ParameterizedTypeReference` argument to convert complex returned types. The template must be configured with a `SmartMessageConverter`. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc b/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc index 18f5107668..f9c89b3e77 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc @@ -90,7 +90,7 @@ public StatefulRetryOperationsInterceptor interceptor() { Only a subset of retry capabilities can be configured this way. More advanced features would need the configuration of a `RetryTemplate` as a Spring bean. -See the https://docs.spring.io/spring-retry/docs/api/current/[Spring Retry Javadoc] for complete information about available policies and their configuration. +See the {spring-retry-java-docs}[Spring Retry Javadoc] for complete information about available policies and their configuration. [[batch-retry]] == Retry with Batch Listeners diff --git a/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc b/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc index 961b8daa13..0d1eaa72da 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc @@ -100,7 +100,7 @@ Message message = MessageBuilder.withBody("foo".getBytes()) .build(); ---- -Each of the properties defined on the https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/core/MessageProperties.html[`MessageProperties`] can be set. +Each of the properties defined on the {spring-amqp-java-docs}/core/MessageProperties.html[`MessageProperties`] can be set. Other methods include `setHeader(String key, String value)`, `removeHeader(String key)`, `removeHeaders()`, and `copyProperties(MessageProperties properties)`. Each property setting method has a `set*IfAbsent()` variant. In the cases where a default initial value exists, the method is named `set*IfAbsentOrDefault()`. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/transactions.adoc b/src/reference/antora/modules/ROOT/pages/amqp/transactions.adoc index c007b02199..59bb842f7b 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/transactions.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/transactions.adoc @@ -69,7 +69,7 @@ If the `channelTransacted` flag was set to `false` (the default) in the precedin Prior to version 1.6.6, adding a rollback rule to a container's `transactionAttribute` when using an external transaction manager (such as JDBC) had no effect. Exceptions always rolled back the transaction. -Also, when using a https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative[transaction advice] in the container's advice chain, conditional rollback was not very useful, because all listener exceptions are wrapped in a `ListenerExecutionFailedException`. +Also, when using a {spring-framework-docs}/data-access/transaction/declarative.html[transaction advice] in the container's advice chain, conditional rollback was not very useful, because all listener exceptions are wrapped in a `ListenerExecutionFailedException`. The first problem has been corrected, and the rules are now applied properly. Further, the `ListenerFailedRuleBasedTransactionAttribute` is now provided. @@ -116,13 +116,13 @@ See xref:amqp/containerAttributes.adoc[Message Listener Container Configuration] [[using-rabbittransactionmanager]] == Using `RabbitTransactionManager` -The https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/transaction/RabbitTransactionManager.html[RabbitTransactionManager] is an alternative to executing Rabbit operations within, and synchronized with, external transactions. -This transaction manager is an implementation of the https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/PlatformTransactionManager.html[`PlatformTransactionManager`] interface and should be used with a single Rabbit `ConnectionFactory`. +The {spring-amqp-java-docs}/rabbit/transaction/RabbitTransactionManager.html[RabbitTransactionManager] is an alternative to executing Rabbit operations within, and synchronized with, external transactions. +This transaction manager is an implementation of the {spring-framework-java-docs}/transaction/PlatformTransactionManager.html[`PlatformTransactionManager`] interface and should be used with a single Rabbit `ConnectionFactory`. IMPORTANT: This strategy is not able to provide XA transactions -- for example, in order to share transactions between messaging and database access. Application code is required to retrieve the transactional Rabbit resources through `ConnectionFactoryUtils.getTransactionalResourceHolder(ConnectionFactory, boolean)` instead of a standard `Connection.createChannel()` call with subsequent channel creation. -When using Spring AMQP's https://docs.spring.io/spring-amqp/docs/latest_ga/api/org/springframework/amqp/rabbit/core/RabbitTemplate.html[RabbitTemplate], it will autodetect a thread-bound Channel and automatically participate in its transaction. +When using Spring AMQP's {spring-amqp-java-docs}/rabbit/core/RabbitTemplate.html[RabbitTemplate], it will autodetect a thread-bound Channel and automatically participate in its transaction. With Java Configuration, you can setup a new RabbitTransactionManager by using the following bean: diff --git a/src/reference/antora/modules/ROOT/pages/appendix/native.adoc b/src/reference/antora/modules/ROOT/pages/appendix/native.adoc index ee924671a2..8234dc91e6 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/native.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/native.adoc @@ -2,6 +2,6 @@ = Native Images :page-section-summary-toc: 1 -https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aot[Spring AOT] native hints are provided to assist in developing native images for Spring applications that use Spring AMQP. +{spring-framework-docs}/core/aot.html[Spring AOT] native hints are provided to assist in developing native images for Spring applications that use Spring AMQP. Some examples can be seen in the https://github.com/spring-projects/spring-aot-smoke-tests/tree/main/integration[`spring-aot-smoke-tests` GitHub repository]. diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc index da13067fff..7aa1b869ff 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc @@ -5,14 +5,14 @@ == Listener Concurrency The listener container now supports dynamic scaling of the number of consumers based on workload, or you can programmatically change the concurrency without stopping the container. -See <>. +See xref:amqp/listener-concurrency.adoc#listener-concurrency[Listener Concurrency]. [[listener-queues]] == Listener Queues The listener container now permits the queues on which it listens to be modified at runtime. Also, the container now starts if at least one of its configured queues is available for use. -See <> +See xref:amqp/listener-queues.adoc#listener-queues[Listener Container Queues] This listener container now redeclares any auto-delete queues during startup. See xref:amqp/receiving-messages/async-consumer.adoc#lc-auto-delete[`auto-delete` Queues]. @@ -21,13 +21,13 @@ See xref:amqp/receiving-messages/async-consumer.adoc#lc-auto-delete[`auto-delete == Consumer Priority The listener container now supports consumer arguments, letting the `x-priority` argument be set. -See <>. +See xref:amqp/receiving-messages/async-consumer.adoc#consumer-priority[Consumer Priority]. [[exclusive-consumer]] == Exclusive Consumer You can now configure `SimpleMessageListenerContainer` with a single `exclusive` consumer, preventing other consumers from listening to the queue. -See <>. +See xref:amqp/exclusive-consumer.adoc[Exclusive Consumer]. [[rabbit-admin]] == Rabbit Admin @@ -47,7 +47,7 @@ If you wish to bind with an empty string routing key, you need to specify `key=" The `AmqpTemplate` now provides several synchronous `receiveAndReply` methods. These are implemented by the `RabbitTemplate`. -For more information see <>. +For more information see xref:amqp/receiving-messages.adoct[Receiving Messages]. The `RabbitTemplate` now supports configuring a `RetryTemplate` to attempt retries (with optional back-off policy) for when the broker is not available. For more information see xref:amqp/template.adoc#template-retry[Adding Retry Capabilities]. @@ -66,12 +66,11 @@ You can now configure the `` of the `` with a `key/va These options are mutually exclusive. See xref:amqp/broker-configuration.adoc#headers-exchange[Headers Exchange]. -[[routing-connection-factory]] == Routing Connection Factory A new `SimpleRoutingConnectionFactory` has been introduced. It allows configuration of `ConnectionFactories` mapping, to determine the target `ConnectionFactory` to use at runtime. -See <>. +See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. [[messagebuilder-and-messagepropertiesbuilder]] == `MessageBuilder` and `MessagePropertiesBuilder` diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc index a4346e4ba4..c43098a182 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc @@ -35,14 +35,14 @@ See xref:amqp/template.adoc#template-confirms[Correlated Publisher Confirms and `RabbitConnectionFactoryBean` creates the underlying RabbitMQ `ConnectionFactory` used by the `CachingConnectionFactory`. This enables configuration of SSL options using Spring's dependency injection. -See <>. +See xref:amqp/connections.adoc#connection-factory[Configuring the Underlying Client Connection Factory]. [[using-cachingconnectionfactory]] == Using `CachingConnectionFactory` The `CachingConnectionFactory` now lets the `connectionTimeout` be set as a property or as an attribute in the namespace. It sets the property on the underlying RabbitMQ `ConnectionFactory`. -See <>. +See xref:amqp/connections.adoc#connection-factory[Configuring the Underlying Client Connection Factory]. [[log-appender]] == Log Appender @@ -71,13 +71,13 @@ The `mandatoryExpression`, `sendConnectionFactorySelectorExpression`, and `recei The `mandatoryExpression` is used to evaluate a `mandatory` boolean value against each request message when a `ReturnCallback` is in use. See xref:amqp/template.adoc#template-confirms[Correlated Publisher Confirms and Returns]. The `sendConnectionFactorySelectorExpression` and `receiveConnectionFactorySelectorExpression` are used when an `AbstractRoutingConnectionFactory` is provided, to determine the `lookupKey` for the target `ConnectionFactory` at runtime on each AMQP protocol interaction operation. -See <>. +See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. [[listeners-and-the-routing-connection-factory]] == Listeners and the Routing Connection Factory You can configure a `SimpleMessageListenerContainer` with a routing connection factory to enable connection selection based on the queue names. -See <>. +See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. [[rabbittemplate:-recoverycallback-option]] == `RabbitTemplate`: `RecoveryCallback` Option diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-5-since-1-4.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-5-since-1-4.adoc index 29282a0033..4b5621cb0e 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-5-since-1-4.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-5-since-1-4.adoc @@ -5,7 +5,7 @@ == `spring-erlang` Is No Longer Supported The `spring-erlang` jar is no longer included in the distribution. -Use <> instead. +Use xref:amqp/management-rest-api.adoc#management-rest-api[RabbitMQ REST API] instead. [[cachingconnectionfactory-changes]] == `CachingConnectionFactory` Changes @@ -122,7 +122,7 @@ See xref:amqp/request-reply.adoc#reply-listener[Reply Listener Container] for mo == `RabbitManagementTemplate` Added The `RabbitManagementTemplate` has been introduced to monitor and configure the RabbitMQ Broker by using the REST API provided by its https://www.rabbitmq.com/management.html[management plugin]. -See <> for more information. +See xref:amqp/management-rest-api.adoc#management-rest-api[RabbitMQ REST API] for more information. [[listener-container-bean-names-xml]] == Listener Container Bean Names (XML) @@ -160,7 +160,7 @@ See xref:amqp/containerAttributes.adoc[Message Listener Container Configuration] == Channel Close Logging A mechanism to control the log levels of channel closure has been introduced. -See <>. +See xref:amqp/connections.adoc#channel-close-logging[Logging Channel Close Events]. [[application-events]] == Application Events diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-6-since-1-5.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-6-since-1-5.adoc index 02d8037f46..2e96f8fea2 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-6-since-1-5.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-6-since-1-5.adoc @@ -189,7 +189,7 @@ See xref:amqp/receiving-messages/async-annotation-driven.adoc[Annotation-driven == Delayed Message Exchange Spring AMQP now has first class support for the RabbitMQ Delayed Message Exchange plugin. -See <> for more information. +See xref:amqp/delayed-message-exchange.adoc[Delayed Message Exchange] for more information. [[exchange-internal-flag]] == Exchange Internal Flag @@ -235,7 +235,7 @@ factory. You can now configure a "`allowed list`" of allowable classes when you use Java deserialization. You should consider creating an allowed list if you accept messages with serialized java objects from untrusted sources. -See <> for more information. +See amqp/message-converters.adoc#java-deserialization[Java Deserialization] for more information. [[json-messageconverter]] == JSON `MessageConverter` diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-7-since-1-6.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-7-since-1-6.adoc index 2c565b3025..054dd56e42 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-7-since-1-6.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-7-since-1-6.adoc @@ -51,7 +51,7 @@ The framework is no longer compatible with previous versions. == JUnit `@Rules` Rules that have previously been used internally by the framework have now been made available in a separate jar called `spring-rabbit-junit`. -See <> for more information. +See xref:testing.adoc#junit-rules[JUnit4 `@Rules`] for more information. [[container-conditional-rollback]] == Container Conditional Rollback diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-0-since-1-7.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-0-since-1-7.adoc index 9355130498..92fd10598b 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-0-since-1-7.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-0-since-1-7.adoc @@ -68,7 +68,7 @@ See xref:amqp/request-reply.adoc#async-template[Async Rabbit Template] for more The `RabbitTemplate` and `AsyncRabbitTemplate` now have `receiveAndConvert` and `convertSendAndReceiveAsType` methods that take a `ParameterizedTypeReference` argument, letting the caller specify the type to which to convert the result. This is particularly useful for complex types or when type information is not conveyed in message headers. It requires a `SmartMessageConverter` such as the `Jackson2JsonMessageConverter`. -See xref:amqp/request-reply.adoc[Request/Reply Messaging], xref:amqp/request-reply.adoc#async-template[Async Rabbit Template], xref:amqp/message-converters.adoc#json-complex[Converting From a `Message` With `RabbitTemplate`], and <> for more information. +See xref:amqp/request-reply.adoc[Request/Reply Messaging], xref:amqp/request-reply.adoc#async-template[Async Rabbit Template], xref:amqp/message-converters.adoc#json-complex[Converting From a `Message` With `RabbitTemplate`], and xref:amqp/message-converters.adoc#json-complex[Converting From a `Message` With `RabbitTemplate`] for more information. You can now use a `RabbitTemplate` to perform multiple operations on a dedicated channel. See xref:amqp/template.adoc#scoped-operations[Scoped Operations] for more information. @@ -179,7 +179,7 @@ See xref:amqp/transactions.adoc#conditional-rollback[Conditional Rollback] for m Deprecated in previous versions, Jackson `1.x` converters and related components have now been deleted. You can use similar components based on Jackson 2.x. -See <> for more information. +See xref:amqp/message-converters.adoc#json-message-converter[`Jackson2JsonMessageConverter`] for more information. [[json-message-converter]] == JSON Message Converter diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-1-since-2-0.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-1-since-2-0.adoc index a905c1899b..07f3bacc9c 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-1-since-2-0.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-1-since-2-0.adoc @@ -81,7 +81,7 @@ See xref:amqp/message-converters.adoc#jackson2xml[`Jackson2XmlMessageConverter`] == Management REST API The `RabbitManagementTemplate` is now deprecated in favor of the direct `com.rabbitmq.http.client.Client` (or `com.rabbitmq.http.client.ReactorNettyClient`) usage. -See <> for more information. +See xref:amqp/management-rest-api.adoc#management-rest-api[RabbitMQ REST API] for more information. [[rabbitlistener-changes]] == `@RabbitListener` Changes diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-to-1-2-since-1-1.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-to-1-2-since-1-1.adoc index 17410e9823..4180c54d78 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-to-1-2-since-1-1.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-to-1-2-since-1-1.adoc @@ -47,7 +47,7 @@ See xref:amqp/broker-configuration.adoc#conditional-declaration[Conditional Decl == AMQP Remoting Facilities are now provided for using Spring remoting techniques, using AMQP as the transport for the RPC calls. -For more information see <> +For more information see xref:amqp/request-reply.adoc#remoting[Spring Remoting with AMQP]. [[requested-heart-beats]] == Requested Heart Beats diff --git a/src/reference/antora/modules/ROOT/pages/integration-reference.adoc b/src/reference/antora/modules/ROOT/pages/integration-reference.adoc index 77745b8955..1dbc762022 100644 --- a/src/reference/antora/modules/ROOT/pages/integration-reference.adoc +++ b/src/reference/antora/modules/ROOT/pages/integration-reference.adoc @@ -13,7 +13,7 @@ We provide an inbound-channel-adapter, an outbound-channel-adapter, an inbound-g Since the AMQP adapters are part of the Spring Integration release, the documentation is available as part of the Spring Integration distribution. We provide a quick overview of the main features here. -See the https://docs.spring.io/spring-integration/reference[Spring Integration Reference Guide] for much more detail. +See the {spring-integration-docs}[Spring Integration Reference Guide] for much more detail. [[inbound-channel-adapter]] == Inbound Channel Adapter diff --git a/src/reference/antora/modules/ROOT/pages/logging.adoc b/src/reference/antora/modules/ROOT/pages/logging.adoc index 21b6855381..cf9b0ff0e5 100644 --- a/src/reference/antora/modules/ROOT/pages/logging.adoc +++ b/src/reference/antora/modules/ROOT/pages/logging.adoc @@ -395,7 +395,7 @@ public class MyEnhancedAppender extends AmqpAppender { } ---- -The Log4j 2 appender supports using a https://logging.apache.org/log4j/2.x/manual/appenders.html#BlockingQueueFactory[`BlockingQueueFactory`], as the following example shows: +The Log4j 2 appender supports using a https://logging.apache.org/log4j/2.x/manual/appenders/delegating.html#BlockingQueueFactory[`BlockingQueueFactory`], as the following example shows: [source, xml] ---- diff --git a/src/reference/antora/modules/ROOT/pages/sample-apps.adoc b/src/reference/antora/modules/ROOT/pages/sample-apps.adoc index bf983d5edc..90a2775e53 100644 --- a/src/reference/antora/modules/ROOT/pages/sample-apps.adoc +++ b/src/reference/antora/modules/ROOT/pages/sample-apps.adoc @@ -20,7 +20,7 @@ You can import the `spring-rabbit-helloworld` sample into the IDE and then follo Within the `src/main/java` directory, navigate to the `org.springframework.amqp.helloworld` package. Open the `HelloWorldConfiguration` class and notice that it contains the `@Configuration` annotation at the class level and notice some `@Bean` annotations at method-level. This is an example of Spring's Java-based configuration. -You can read more about that https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java[here]. +You can read more about that {spring-framework-docs}/core/beans/java.html[here]. The following listing shows how the connection factory is created: @@ -144,7 +144,7 @@ static class ScheduledProducer { ---- You do not need to understand all of the details, since the real focus should be on the receiving side (which we cover next). -However, if you are not yet familiar with Spring task scheduling support, you can learn more https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-annotation-support[here]. +However, if you are not yet familiar with Spring task scheduling support, you can learn more {spring-framework-docs}/integration/scheduling.html#scheduling-annotation-support-scheduled[here]. The short story is that the `postProcessor` bean in the `ProducerConfiguration` registers the task with a scheduler. Now we can turn to the receiving side. @@ -351,4 +351,4 @@ Spring applications, when sending JSON, set the `__TypeId__` header to the fully The `spring-rabbit-json` sample explores several techniques to convert the JSON from a non-Spring application. -See also xref:amqp/message-converters.adoc#json-message-converter[`Jackson2JsonMessageConverter`] as well as the https://docs.spring.io/spring-amqp/docs/current/api/index.html?org/springframework/amqp/support/converter/DefaultClassMapper.html[Javadoc for the `DefaultClassMapper`]. +See also xref:amqp/message-converters.adoc#json-message-converter[`Jackson2JsonMessageConverter`] as well as the {spring-amqp-java-docs}/index.html?org/springframework/amqp/support/converter/DefaultClassMapper.html[Javadoc for the `DefaultClassMapper`]. diff --git a/src/reference/antora/modules/ROOT/pages/stream.adoc b/src/reference/antora/modules/ROOT/pages/stream.adoc index 4994354fca..8943b31695 100644 --- a/src/reference/antora/modules/ROOT/pages/stream.adoc +++ b/src/reference/antora/modules/ROOT/pages/stream.adoc @@ -109,7 +109,7 @@ You can also send native stream `Message` s directly; with the `messageBuilder() The `ProducerCustomizer` provides a mechanism to customize the producer before it is built. -Refer to the https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle/[Java Client Documentation] about customizing the `Environment` and `Producer`. +Refer to the {rabbitmq-stream-docs}[Java Client Documentation] about customizing the `Environment` and `Producer`. IMPORTANT: Starting with version 3.0, the method return types are `CompletableFuture` instead of `ListenableFuture`. @@ -135,7 +135,7 @@ See xref:amqp/containerAttributes.adoc[Message Listener Container Configuration] Similar the template, the container has a `ConsumerCustomizer` property. -Refer to the https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle/[Java Client Documentation] about customizing the `Environment` and `Consumer`. +Refer to the {rabbitmq-stream-docs}[Java Client Documentation] about customizing the `Environment` and `Consumer`. When using `@RabbitListener`, configure a `StreamRabbitListenerContainerFactory`; at this time, most `@RabbitListener` properties (`concurrency`, etc) are ignored. Only `id`, `queues`, `autoStartup` and `containerFactory` are supported. In addition, `queues` can only contain one stream name. @@ -287,7 +287,7 @@ StreamListenerContainer container(Environment env, String name) { ---- IMPORTANT: At this time, when the concurrency is greater than 1, the actual concurrency is further controlled by the `Environment`; to achieve full concurrency, set the environment's `maxConsumersByConnection` to 1. -See https://rabbitmq.github.io/rabbitmq-stream-java-client/snapshot/htmlsingle/#configuring-the-environment[Configuring the Environment]. +See {rabbitmq-stream-docs}/#configuring-the-environment[Configuring the Environment]. [[stream-micrometer-observation]] == Micrometer Observation @@ -298,7 +298,7 @@ The container now also supports Micrometer timers (when observation is not enabl Set `observationEnabled` on each component to enable observation; this will disable xref:amqp/receiving-messages/micrometer.adoc[Micrometer Timers] because the timers will now be managed with each observation. When using annotated listeners, set `observationEnabled` on the container factory. -Refer to https://docs.micrometer.io/tracing/reference/[Micrometer Tracing] for more information. +Refer to {micrometer-tracing-docs}[Micrometer Tracing] for more information. To add tags to timers/traces, configure a custom `RabbitStreamTemplateObservationConvention` or `RabbitStreamListenerObservationConvention` to the template or listener container, respectively. From 2a634227703ef57adbe4a8994fbd08066108b273 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 16 Sep 2024 14:52:52 -0400 Subject: [PATCH 011/111] Remove explicit `com.gradle.develocity` plugin It is managed now transitively by the `io.spring.develocity.conventions` **Auto-cherry-pick to `3.1.x`** --- settings.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 5c20e31b03..87c12dd0fa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,6 @@ pluginManagement { } plugins { - id 'com.gradle.develocity' version '3.17.6' id 'io.spring.develocity.conventions' version '0.0.21' } From 308841b1cd5e008624aad774abe2f2eedba2ca58 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 16 Sep 2024 15:05:20 -0400 Subject: [PATCH 012/111] Upgrade deps to milestones; prepare for release * Update to the latest available third-party dependencies --- build.gradle | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index fddd060b39..ae0a260db7 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ ext { assertjVersion = '3.26.3' assertkVersion = '0.28.1' awaitilityVersion = '4.2.2' - commonsCompressVersion = '1.26.2' + commonsCompressVersion = '1.27.1' commonsHttpClientVersion = '5.3.1' commonsPoolVersion = '2.12.0' hamcrestVersion = '2.2' @@ -58,21 +58,21 @@ ext { junit4Version = '4.13.2' junitJupiterVersion = '5.11.0' kotlinCoroutinesVersion = '1.8.1' - log4jVersion = '2.23.1' + log4jVersion = '2.24.0' logbackVersion = '1.5.8' lz4Version = '1.8.0' micrometerDocsVersion = '1.0.4' - micrometerVersion = '1.14.0-SNAPSHOT' - micrometerTracingVersion = '1.4.0-SNAPSHOT' - mockitoVersion = '5.12.0' + micrometerVersion = '1.14.0-M3' + micrometerTracingVersion = '1.4.0-M3' + mockitoVersion = '5.13.0' rabbitmqStreamVersion = '0.15.0' rabbitmqVersion = '5.21.0' - reactorVersion = '2024.0.0-SNAPSHOT' + reactorVersion = '2024.0.0-M6' snappyVersion = '1.1.10.7' springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' - springVersion = '6.2.0-SNAPSHOT' - testcontainersVersion = '1.19.8' + springVersion = '6.2.0-RC1' + testcontainersVersion = '1.20.1' zstdJniVersion = '1.5.6-5' javaProjects = subprojects - project(':spring-amqp-bom') From 1e188c3b8828af90ed78acdd2f6fdae7c8d98252 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 16 Sep 2024 15:33:54 -0400 Subject: [PATCH 013/111] Fix link in the `changes-in-1-3-since-1-2.adoc` --- .../appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc index 7aa1b869ff..5c5948f7d2 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc @@ -47,7 +47,7 @@ If you wish to bind with an empty string routing key, you need to specify `key=" The `AmqpTemplate` now provides several synchronous `receiveAndReply` methods. These are implemented by the `RabbitTemplate`. -For more information see xref:amqp/receiving-messages.adoct[Receiving Messages]. +For more information see xref:amqp/receiving-messages.adoc[Receiving Messages]. The `RabbitTemplate` now supports configuring a `RetryTemplate` to attempt retries (with optional back-off policy) for when the broker is not available. For more information see xref:amqp/template.adoc#template-retry[Adding Retry Capabilities]. From 98d9df89b34f1037ee5bd10bbacd857c60640804 Mon Sep 17 00:00:00 2001 From: Spring Builds Date: Mon, 16 Sep 2024 19:40:00 +0000 Subject: [PATCH 014/111] [artifactory-release] Release version 3.2.0-M3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6bc0422ab1..b000448eff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.2.0-SNAPSHOT +version=3.2.0-M3 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8 org.gradle.daemon=true org.gradle.caching=true From 52ff8d1257608de070f19d7ac060f986996a577f Mon Sep 17 00:00:00 2001 From: Spring Builds Date: Mon, 16 Sep 2024 19:40:02 +0000 Subject: [PATCH 015/111] [artifactory-release] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b000448eff..6bc0422ab1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.2.0-M3 +version=3.2.0-SNAPSHOT org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8 org.gradle.daemon=true org.gradle.caching=true From b4339b3c615c748264b1c5188c62028234eba591 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Tue, 17 Sep 2024 22:52:12 +0700 Subject: [PATCH 016/111] More link fixes in docs --- src/reference/antora/antora.yml | 4 +++- .../antora/modules/ROOT/pages/amqp/abstractions.adoc | 2 +- src/reference/antora/modules/ROOT/pages/amqp/connections.adoc | 2 +- .../antora/modules/ROOT/pages/amqp/containerAttributes.adoc | 2 +- .../antora/modules/ROOT/pages/amqp/management-rest-api.adoc | 2 +- .../appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc | 2 +- .../appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc | 4 ++-- .../appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc | 2 +- src/reference/antora/modules/ROOT/pages/stream.adoc | 2 +- 9 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/reference/antora/antora.yml b/src/reference/antora/antora.yml index f3ceb248f4..a3fb163dea 100644 --- a/src/reference/antora/antora.yml +++ b/src/reference/antora/antora.yml @@ -25,4 +25,6 @@ asciidoc: micrometer-docs: 'https://docs.micrometer.io' micrometer-tracing-docs: '{micrometer-docs}/tracing/reference/' micrometer-micrometer-docs: '{micrometer-docs}/micrometer/reference/' - rabbitmq-stream-docs: 'https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle' \ No newline at end of file + rabbitmq-stream-docs: 'https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle' + rabbitmq-github: 'https://github.com/rabbitmq' + rabbitmq-server-github: '{rabbitmq-github}/rabbitmq-server/tree/main/deps' \ No newline at end of file diff --git a/src/reference/antora/modules/ROOT/pages/amqp/abstractions.adoc b/src/reference/antora/modules/ROOT/pages/amqp/abstractions.adoc index b86178a244..9d7bad429f 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/abstractions.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/abstractions.adoc @@ -93,7 +93,7 @@ Starting with version 3.2, the `ConsistentHashExchange` type has been introduced It provided options like `x-consistent-hash` for an exchange type. Allows to configure `hash-header` or `hash-property` exchange definition argument. The respective RabbitMQ `rabbitmq_consistent_hash_exchange` plugin has to be enabled on the broker. -More information about the purpose, logic and behavior of the Consistent Hash Exchange are in the official RabbitMQ https://github.com/rabbitmq/rabbitmq-server/tree/main/deps/rabbitmq_consistent_hash_exchange[documentation]. +More information about the purpose, logic and behavior of the Consistent Hash Exchange are in the official RabbitMQ {rabbitmq-server-github}/rabbitmq_consistent_hash_exchange[documentation]. NOTE: The AMQP specification also requires that any broker provide a "`default`" direct exchange that has no name. All queues that are declared are bound to that default `Exchange` with their names as routing keys. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc b/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc index da8bf568b8..c1b278a820 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/connections.adoc @@ -429,7 +429,7 @@ Starting with version 3.0, the underlying connection factory will attempt to con To revert to the previous behavior of attempting to connect from first to last, set the `addressShuffleMode` property to `AddressShuffleMode.NONE`. Starting with version 2.3, the `INORDER` shuffle mode was added, which means the first address is moved to the end after a connection is created. -You may wish to use this mode with the https://github.com/rabbitmq/rabbitmq-sharding[RabbitMQ Sharding Plugin] with `CacheMode.CONNECTION` and suitable concurrency if you wish to consume from all shards on all nodes. +You may wish to use this mode with the {rabbitmq-server-github}/rabbitmq_sharding[RabbitMQ Sharding Plugin] with `CacheMode.CONNECTION` and suitable concurrency if you wish to consume from all shards on all nodes. [source, java] ---- diff --git a/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc b/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc index 9aec7d7c9b..f876898405 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc @@ -250,7 +250,7 @@ a| |[[consumeDelay]]<> + (N/A) -|When using the https://github.com/rabbitmq/rabbitmq-sharding[RabbitMQ Sharding Plugin] with `concurrentConsumers > 1`, there is a race condition that can prevent even distribution of the consumers across the shards. +|When using the {rabbitmq-server-github}/rabbitmq_sharding[RabbitMQ Sharding Plugin] with `concurrentConsumers > 1`, there is a race condition that can prevent even distribution of the consumers across the shards. Use this property to add a small delay between consumer starts to avoid this race condition. You should experiment with values to determine the suitable delay for your environment. diff --git a/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc b/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc index a693e1e36d..628c0ff7b1 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/management-rest-api.adoc @@ -3,7 +3,7 @@ :page-section-summary-toc: 1 When the management plugin is enabled, the RabbitMQ server exposes a REST API to monitor and configure the broker. -A https://github.com/rabbitmq/hop[Java Binding for the API] is now provided. +A {rabbitmq-github}/hop[Java Binding for the API] is now provided. The `com.rabbitmq.http.client.Client` is a standard, immediate, and, therefore, blocking API. It is based on the {spring-framework-docs}/web.html[Spring Web] module and its `RestTemplate` implementation. On the other hand, the `com.rabbitmq.http.client.ReactorNettyClient` is a reactive, non-blocking implementation based on the https://projectreactor.io/docs/netty/release/reference/docs/index.html[Reactor Netty] project. diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc index 5c5948f7d2..41ddf37416 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-3-since-1-2.adoc @@ -70,7 +70,7 @@ See xref:amqp/broker-configuration.adoc#headers-exchange[Headers Exchange]. A new `SimpleRoutingConnectionFactory` has been introduced. It allows configuration of `ConnectionFactories` mapping, to determine the target `ConnectionFactory` to use at runtime. -See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. +See xref:amqp/connections.adoc#routing-connection-factory[Routing Connection Factory]. [[messagebuilder-and-messagepropertiesbuilder]] == `MessageBuilder` and `MessagePropertiesBuilder` diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc index c43098a182..fef889d846 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc @@ -71,13 +71,13 @@ The `mandatoryExpression`, `sendConnectionFactorySelectorExpression`, and `recei The `mandatoryExpression` is used to evaluate a `mandatory` boolean value against each request message when a `ReturnCallback` is in use. See xref:amqp/template.adoc#template-confirms[Correlated Publisher Confirms and Returns]. The `sendConnectionFactorySelectorExpression` and `receiveConnectionFactorySelectorExpression` are used when an `AbstractRoutingConnectionFactory` is provided, to determine the `lookupKey` for the target `ConnectionFactory` at runtime on each AMQP protocol interaction operation. -See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. +See xref:amqp/connections.adoc#routing-connection-factory[Routing Connection Factory]. [[listeners-and-the-routing-connection-factory]] == Listeners and the Routing Connection Factory You can configure a `SimpleMessageListenerContainer` with a routing connection factory to enable connection selection based on the queue names. -See xref:amqp/connections.adoc#routing-connection-factory[routing-connection-factory]. +See xref:amqp/connections.adoc#routing-connection-factory[Routing Connection Factory]. [[rabbittemplate:-recoverycallback-option]] == `RabbitTemplate`: `RecoveryCallback` Option diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc index d49bf3128f..fca45e9164 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc @@ -43,7 +43,7 @@ See xref:amqp/request-reply.adoc#direct-reply-to[RabbitMQ Direct reply-to] for m [[listener-container-changes]] == Listener Container Changes -A new listener container property `consumeDelay` is now available; it is helpful when using the https://github.com/rabbitmq/rabbitmq-sharding[RabbitMQ Sharding Plugin]. +A new listener container property `consumeDelay` is now available; it is helpful when using the {rabbitmq-server-github}/rabbitmq_sharding[RabbitMQ Sharding Plugin]. The default `JavaLangErrorHandler` now calls `System.exit(99)`. To revert to the previous behavior (do nothing), add a no-op handler. diff --git a/src/reference/antora/modules/ROOT/pages/stream.adoc b/src/reference/antora/modules/ROOT/pages/stream.adoc index 8943b31695..e9f5119e03 100644 --- a/src/reference/antora/modules/ROOT/pages/stream.adoc +++ b/src/reference/antora/modules/ROOT/pages/stream.adoc @@ -1,7 +1,7 @@ [[stream-support]] = Using the RabbitMQ Stream Plugin -Version 2.4 introduces initial support for the https://github.com/rabbitmq/rabbitmq-stream-java-client[RabbitMQ Stream Plugin Java Client] for the https://rabbitmq.com/stream.html[RabbitMQ Stream Plugin]. +Version 2.4 introduces initial support for the {rabbitmq-github}/rabbitmq-stream-java-client[RabbitMQ Stream Plugin Java Client] for the https://rabbitmq.com/stream.html[RabbitMQ Stream Plugin]. * `RabbitStreamTemplate` * `StreamListenerContainer` From aa21c73500085fe50bbd62ac05f8df5cd1a1e6e4 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 18 Sep 2024 16:27:36 -0400 Subject: [PATCH 017/111] Migrate to `DEVELOCITY_ACCESS_KEY` secret for GHA workflows **Auto-cherry-pick to `3.1.x`** --- .github/workflows/ci-snapshot.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/verify-staged-artifacts.yml | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index c57e8778e7..a7191a1997 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -17,10 +17,10 @@ concurrency: jobs: build-snapshot: - uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-snapshot.yml@v3 + uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-snapshot.yml@main with: gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} secrets: - GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c0bea04ccc..c2a43c3e96 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@main secrets: GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} JF_ARTIFACTORY_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} diff --git a/.github/workflows/verify-staged-artifacts.yml b/.github/workflows/verify-staged-artifacts.yml index bee9abc943..979726f519 100644 --- a/.github/workflows/verify-staged-artifacts.yml +++ b/.github/workflows/verify-staged-artifacts.yml @@ -10,9 +10,7 @@ on: env: - GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }} - GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} - GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} From ed0d7905ac74f13a7c02433e545010dcc6458e4e Mon Sep 17 00:00:00 2001 From: vmeunier Date: Thu, 19 Sep 2024 21:24:33 +0200 Subject: [PATCH 018/111] GH-2814: OTel tags for RabbitTemplate and RabbitListener Fixes: #2814 Issue link: https://github.com/spring-projects/spring-amqp/issues/2814 * Add Opentelemetry tags `RabbitTemplate ` * Add Opentelemetry tags `RabbitListenerObservationConvention` --- .../micrometer/RabbitListenerObservation.java | 43 +++++++++++++-- .../micrometer/RabbitTemplateObservation.java | 37 ++++++++++++- .../ObservationIntegrationTests.java | 55 ++++++++++++++----- 3 files changed, 113 insertions(+), 22 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java index b580bd2e7e..f5f8528491 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,8 @@ * Spring Rabbit Observation for listeners. * * @author Gary Russell + * @author Vincent Meunier * @since 3.0 - * */ public enum RabbitListenerObservation implements ObservationDocumentation { @@ -36,7 +36,6 @@ public enum RabbitListenerObservation implements ObservationDocumentation { */ LISTENER_OBSERVATION { - @Override public Class> getDefaultConvention() { return DefaultRabbitListenerObservationConvention.class; @@ -69,6 +68,34 @@ public String asString() { return "spring.rabbit.listener.id"; } + }, + + /** + * The queue the listener is plugged to. + * + * @since 3.2 + */ + DESTINATION_NAME { + + @Override + public String asString() { + return "messaging.destination.name"; + } + + }, + + /** + * The delivery tag. + * + * @since 3.2 + */ + DELIVERY_TAG { + + @Override + public String asString() { + return "messaging.rabbitmq.message.delivery_tag"; + } + } } @@ -86,8 +113,14 @@ public static class DefaultRabbitListenerObservationConvention implements Rabbit @Override public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context) { - return KeyValues.of(RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(), - context.getListenerId()); + final var messageProperties = context.getCarrier().getMessageProperties(); + return KeyValues.of( + RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(), context.getListenerId(), + RabbitListenerObservation.ListenerLowCardinalityTags.DESTINATION_NAME.asString(), + messageProperties.getConsumerQueue(), + RabbitListenerObservation.ListenerLowCardinalityTags.DELIVERY_TAG.asString(), + String.valueOf(messageProperties.getDeliveryTag()) + ); } @Override diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java index f3bc17f1e6..6008e1e06d 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ * Spring RabbitMQ Observation for {@link org.springframework.amqp.rabbit.core.RabbitTemplate}. * * @author Gary Russell + * @author Vincent Meunier * @since 3.0 * */ @@ -68,8 +69,35 @@ public String asString() { return "spring.rabbit.template.name"; } + }, + + /** + * The destination exchange (empty if default exchange). + * @since 3.2 + */ + EXCHANGE { + + @Override + public String asString() { + return "messaging.destination.name"; + } + + }, + + /** + * The destination routing key. + * @since 3.2 + */ + ROUTING_KEY { + + @Override + public String asString() { + return "messaging.rabbitmq.destination.routing_key"; + } + } + } /** @@ -85,8 +113,11 @@ public static class DefaultRabbitTemplateObservationConvention implements Rabbit @Override public KeyValues getLowCardinalityKeyValues(RabbitMessageSenderContext context) { - return KeyValues.of(RabbitTemplateObservation.TemplateLowCardinalityTags.BEAN_NAME.asString(), - context.getBeanName()); + return KeyValues.of( + TemplateLowCardinalityTags.BEAN_NAME.asString(), context.getBeanName(), + TemplateLowCardinalityTags.EXCHANGE.asString(), context.getExchange(), + TemplateLowCardinalityTags.ROUTING_KEY.asString(), context.getRoutingKey() + ); } @Override diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java index 41c7facb86..920deec403 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.EnableRabbit; @@ -35,6 +34,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; import io.micrometer.core.tck.MeterRegistryAssert; import io.micrometer.observation.ObservationRegistry; @@ -47,7 +47,6 @@ /** * @author Artem Bilan * @author Gary Russell - * * @since 3.0 */ @RabbitAvailable(queues = { "int.observation.testQ1", "int.observation.testQ2" }) @@ -72,40 +71,69 @@ public SampleTestRunnerConsumer yourCode() { .hasSize(4); List producerSpans = finishedSpans.stream() .filter(span -> span.getKind().equals(Kind.PRODUCER)) - .collect(Collectors.toList()); + .toList(); List consumerSpans = finishedSpans.stream() .filter(span -> span.getKind().equals(Kind.CONSUMER)) - .collect(Collectors.toList()); + .toList(); SpanAssert.assertThat(producerSpans.get(0)) - .hasTag("spring.rabbit.template.name", "template"); + .hasTag("spring.rabbit.template.name", "template") + .hasTag("messaging.destination.name", "") + .hasTag("messaging.rabbitmq.destination.routing_key", "int.observation.testQ1"); SpanAssert.assertThat(producerSpans.get(0)) .hasRemoteServiceNameEqualTo("RabbitMQ"); SpanAssert.assertThat(producerSpans.get(1)) - .hasTag("spring.rabbit.template.name", "template"); + .hasTag("spring.rabbit.template.name", "template") + .hasTag("messaging.destination.name", "") + .hasTag("messaging.rabbitmq.destination.routing_key", "int.observation.testQ2"); SpanAssert.assertThat(consumerSpans.get(0)) - .hasTagWithKey("spring.rabbit.listener.id"); + .hasTagWithKey("spring.rabbit.listener.id") + .hasTag("messaging.destination.name", "int.observation.testQ1") + .hasTag("messaging.rabbitmq.message.delivery_tag", "1"); SpanAssert.assertThat(consumerSpans.get(0)) .hasRemoteServiceNameEqualTo("RabbitMQ"); assertThat(consumerSpans.get(0).getTags().get("spring.rabbit.listener.id")).isIn("obs1", "obs2"); SpanAssert.assertThat(consumerSpans.get(1)) .hasTagWithKey("spring.rabbit.listener.id"); assertThat(consumerSpans.get(1).getTags().get("spring.rabbit.listener.id")).isIn("obs1", "obs2"); + SpanAssert.assertThat(consumerSpans.get(1)) + .hasTagWithKey("spring.rabbit.listener.id") + .hasTag("messaging.destination.name", "int.observation.testQ2") + .hasTag("messaging.rabbitmq.message.delivery_tag", "1"); assertThat(consumerSpans.get(0).getTags().get("spring.rabbit.listener.id")) .isNotEqualTo(consumerSpans.get(1).getTags().get("spring.rabbit.listener.id")); MeterRegistryAssert.assertThat(getMeterRegistry()) .hasTimerWithNameAndTags("spring.rabbit.template", - KeyValues.of("spring.rabbit.template.name", "template")) + KeyValues.of( + KeyValue.of("spring.rabbit.template.name", "template"), + KeyValue.of("messaging.destination.name", ""), + KeyValue.of("messaging.rabbitmq.destination.routing_key", "int.observation.testQ1") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.template", - KeyValues.of("spring.rabbit.template.name", "template")) + KeyValues.of( + KeyValue.of("spring.rabbit.template.name", "template"), + KeyValue.of("messaging.destination.name", ""), + KeyValue.of("messaging.rabbitmq.destination.routing_key", "int.observation.testQ2") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.listener", - KeyValues.of("spring.rabbit.listener.id", "obs1")) + KeyValues.of( + KeyValue.of("spring.rabbit.listener.id", "obs1"), + KeyValue.of("messaging.destination.name", "int.observation.testQ1"), + KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1") + ) + ) .hasTimerWithNameAndTags("spring.rabbit.listener", - KeyValues.of("spring.rabbit.listener.id", "obs2")); + KeyValues.of( + KeyValue.of("spring.rabbit.listener.id", "obs2"), + KeyValue.of("messaging.destination.name", "int.observation.testQ2"), + KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1") + ) + ); }; } - @Configuration @EnableRabbit public static class Config { @@ -159,5 +187,4 @@ void listen2(Message in) { } - } From ed8f13ce4564129bc35373451c3fcc365176745f Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 20 Sep 2024 13:52:36 -0400 Subject: [PATCH 019/111] Migrate to `DEVELOCITY_ACCESS_KEY` secret for GHA **Auto-cherry-pick to `3.1.x`** --- .github/workflows/ci-snapshot.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/verify-staged-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index a7191a1997..a21192cd2c 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -21,6 +21,6 @@ jobs: with: gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} secrets: - DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c2a43c3e96..90f17f1609 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@main secrets: GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} JF_ARTIFACTORY_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} diff --git a/.github/workflows/verify-staged-artifacts.yml b/.github/workflows/verify-staged-artifacts.yml index 979726f519..9a83a2024d 100644 --- a/.github/workflows/verify-staged-artifacts.yml +++ b/.github/workflows/verify-staged-artifacts.yml @@ -10,7 +10,7 @@ on: env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} From 3111a601ae1d4f18cc52d0ec36dd4acab52cddc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:03:04 +0000 Subject: [PATCH 020/111] Bump io.micrometer:micrometer-bom from 1.14.0-M3 to 1.14.0-SNAPSHOT (#2834) Bumps [io.micrometer:micrometer-bom](https://github.com/micrometer-metrics/micrometer) from 1.14.0-M3 to 1.14.0-SNAPSHOT. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/commits) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ae0a260db7..d4a718976f 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ ext { logbackVersion = '1.5.8' lz4Version = '1.8.0' micrometerDocsVersion = '1.0.4' - micrometerVersion = '1.14.0-M3' + micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-M3' mockitoVersion = '5.13.0' rabbitmqStreamVersion = '0.15.0' From 6b0c889fae85984e30cb9adeb5e22d09c80bf227 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:05:06 +0000 Subject: [PATCH 021/111] Bump io.projectreactor:reactor-bom from 2024.0.0-M6 to 2024.0.0-SNAPSHOT (#2837) Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2024.0.0-M6 to 2024.0.0-SNAPSHOT. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/commits) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d4a718976f..64779e3104 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ ext { mockitoVersion = '5.13.0' rabbitmqStreamVersion = '0.15.0' rabbitmqVersion = '5.21.0' - reactorVersion = '2024.0.0-M6' + reactorVersion = '2024.0.0-SNAPSHOT' snappyVersion = '1.1.10.7' springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' From 8c714fa708f0140d58fabbdcece4b18d3bcda90b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:05:26 +0000 Subject: [PATCH 022/111] Bump org.springframework:spring-framework-bom (#2835) Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.0-RC1 to 6.2.0-SNAPSHOT. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/commits) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 64779e3104..cec6251a24 100644 --- a/build.gradle +++ b/build.gradle @@ -71,7 +71,7 @@ ext { snappyVersion = '1.1.10.7' springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' - springVersion = '6.2.0-RC1' + springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.20.1' zstdJniVersion = '1.5.6-5' From 872a56462f746e753c22717971191c72735ba269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 02:06:35 +0000 Subject: [PATCH 023/111] Bump io.micrometer:micrometer-tracing-bom (#2836) Bumps [io.micrometer:micrometer-tracing-bom](https://github.com/micrometer-metrics/tracing) from 1.4.0-M3 to 1.4.0-SNAPSHOT. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/commits) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cec6251a24..284c3366ec 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ ext { lz4Version = '1.8.0' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' - micrometerTracingVersion = '1.4.0-M3' + micrometerTracingVersion = '1.4.0-SNAPSHOT' mockitoVersion = '5.13.0' rabbitmqStreamVersion = '0.15.0' rabbitmqVersion = '5.21.0' From 951781544a42e6e26ffe85d6eda621cff31aed9c Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 23 Sep 2024 21:58:06 +0700 Subject: [PATCH 024/111] Modernize code for diamond operator * Use `isEmpty()` instead for length for `String` or `Collection` --- .../springframework/amqp/core/AbstractBuilder.java | 5 +++-- .../springframework/amqp/core/AbstractDeclarable.java | 9 +++++---- .../org/springframework/amqp/core/BindingBuilder.java | 9 +++++---- .../amqp/support/SimpleAmqpHeaderMapper.java | 3 ++- .../support/converter/AbstractJavaTypeMapper.java | 7 ++++--- .../AllowedListDeserializingMessageConverter.java | 5 +++-- .../ContentTypeDelegatingMessageConverter.java | 5 +++-- .../converter/DefaultJackson2JavaTypeMapper.java | 5 +++-- .../DelegatingDecompressingPostProcessor.java | 5 +++-- .../postprocessor/MessagePostProcessorUtils.java | 11 ++++++----- .../org/springframework/amqp/utils/MapBuilder.java | 5 +++-- .../amqp/rabbit/AsyncRabbitTemplate.java | 7 ++++--- .../RabbitListenerAnnotationBeanPostProcessor.java | 4 ++-- .../amqp/rabbit/batch/SimpleBatchingStrategy.java | 5 +++-- .../amqp/rabbit/config/AbstractExchangeParser.java | 5 +++-- .../amqp/rabbit/config/NamespaceUtils.java | 5 +++-- .../connection/AbstractRoutingConnectionFactory.java | 7 ++++--- .../rabbit/connection/CompositeChannelListener.java | 7 ++++--- .../connection/CompositeConnectionListener.java | 7 ++++--- .../rabbit/connection/ConsumerChannelRegistry.java | 5 +++-- .../connection/LocalizedQueueConnectionFactory.java | 7 ++++--- .../connection/PublisherCallbackChannelImpl.java | 9 +++++---- .../amqp/rabbit/connection/RabbitResourceHolder.java | 5 +++-- .../amqp/rabbit/connection/SimpleResourceHolder.java | 9 +++++---- .../listener/AbstractRabbitListenerEndpoint.java | 5 +++-- .../listener/ConditionalRejectingErrorHandler.java | 5 +++-- .../listener/MultiMethodRabbitListenerEndpoint.java | 5 +++-- .../amqp/rabbit/support/ActiveObjectCounter.java | 7 ++++--- 28 files changed, 100 insertions(+), 73 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractBuilder.java b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractBuilder.java index fe09c2b6d6..30506f62ca 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractBuilder.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2016-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ * Base class for builders supporting arguments. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.6 * */ @@ -36,7 +37,7 @@ public abstract class AbstractBuilder { */ protected Map getOrCreateArguments() { if (this.arguments == null) { - this.arguments = new LinkedHashMap(); + this.arguments = new LinkedHashMap<>(); } return this.arguments; } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java index 83002a2ec3..678620e914 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ * * @author Gary Russell * @author Christian Tzolov + * @author Ngoc Nhan * @since 1.2 * */ @@ -43,7 +44,7 @@ public abstract class AbstractDeclarable implements Declarable { private boolean shouldDeclare = true; - private Collection declaringAdmins = new ArrayList(); + private Collection declaringAdmins = new ArrayList<>(); private boolean ignoreDeclarationExceptions; @@ -63,7 +64,7 @@ public AbstractDeclarable(@Nullable Map arguments) { this.arguments = new HashMap<>(arguments); } else { - this.arguments = new HashMap(); + this.arguments = new HashMap<>(); } } @@ -102,7 +103,7 @@ public void setIgnoreDeclarationExceptions(boolean ignoreDeclarationExceptions) @Override public void setAdminsThatShouldDeclare(Object... adminArgs) { - Collection admins = new ArrayList(); + Collection admins = new ArrayList<>(); if (adminArgs != null) { if (adminArgs.length > 1) { Assert.noNullElements(adminArgs, "'admins' cannot contain null elements"); diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java index 642481750d..956d83d8ec 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ * @author Mark Fisher * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan */ public final class BindingBuilder { @@ -50,7 +51,7 @@ public static DestinationConfigurer bind(Exchange exchange) { } private static Map createMapForKeys(String... keys) { - Map map = new HashMap(); + Map map = new HashMap<>(); for (String key : keys) { map.put(key, null); } @@ -155,7 +156,7 @@ public Binding exists() { } public Binding matches(Object value) { - Map map = new HashMap(); + Map map = new HashMap<>(); map.put(this.key, value); return new Binding(HeadersExchangeMapConfigurer.this.destination.queue, HeadersExchangeMapConfigurer.this.destination.name, @@ -194,7 +195,7 @@ public final class HeadersExchangeMapBindingCreator { HeadersExchangeMapBindingCreator(Map headerMap, boolean matchAll) { Assert.notEmpty(headerMap, "header map must not be empty"); - this.headerMap = new HashMap(headerMap); + this.headerMap = new HashMap<>(headerMap); this.headerMap.put("x-match", (matchAll ? "all" : "any")); } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java b/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java index 2c9a35864b..2885f91f46 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java @@ -49,6 +49,7 @@ * @author Artem Bilan * @author Stephane Nicoll * @author Raylax Grey + * @author Ngoc Nhan * @since 1.4 */ public class SimpleAmqpHeaderMapper extends AbstractHeaderMapper implements AmqpHeaderMapper { @@ -125,7 +126,7 @@ public void fromHeaders(MessageHeaders headers, MessageProperties amqpMessagePro @Override public MessageHeaders toHeaders(MessageProperties amqpMessageProperties) { - Map headers = new HashMap(); + Map headers = new HashMap<>(); try { BiConsumer putObject = headers::put; BiConsumer putString = headers::put; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java index 4745f9623d..76531523be 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ * @author Sam Nelson * @author Andreas Asplund * @author Gary Russell + * @author Ngoc Nhan */ public abstract class AbstractJavaTypeMapper implements BeanClassLoaderAware { @@ -44,9 +45,9 @@ public abstract class AbstractJavaTypeMapper implements BeanClassLoaderAware { public static final String DEFAULT_KEY_CLASSID_FIELD_NAME = "__KeyTypeId__"; - private final Map> idClassMapping = new HashMap>(); + private final Map> idClassMapping = new HashMap<>(); - private final Map, String> classIdMapping = new HashMap, String>(); + private final Map, String> classIdMapping = new HashMap<>(); private ClassLoader classLoader = ClassUtils.getDefaultClassLoader(); diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AllowedListDeserializingMessageConverter.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AllowedListDeserializingMessageConverter.java index 14d6247ddd..4f5e6d24ae 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AllowedListDeserializingMessageConverter.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AllowedListDeserializingMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2016-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,12 +27,13 @@ * MessageConverters that potentially use Java deserialization. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.5.5 * */ public abstract class AllowedListDeserializingMessageConverter extends AbstractMessageConverter { - private final Set allowedListPatterns = new LinkedHashSet(); + private final Set allowedListPatterns = new LinkedHashSet<>(); /** * Set simple patterns for allowable packages/classes for deserialization. diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java index 735d928ac5..0fad672ee1 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,11 +33,12 @@ * @author Eric Rizzo * @author Gary Russell * @author Artem Bilan + * @author Ngoc Nhan * @since 1.4.2 */ public class ContentTypeDelegatingMessageConverter implements MessageConverter { - private final Map delegates = new HashMap(); + private final Map delegates = new HashMap<>(); private final MessageConverter defaultConverter; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/DefaultJackson2JavaTypeMapper.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/DefaultJackson2JavaTypeMapper.java index ed3423efa8..380892662b 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/DefaultJackson2JavaTypeMapper.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/DefaultJackson2JavaTypeMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ * @author Andreas Asplund * @author Artem Bilan * @author Gary Russell + * @author Ngoc Nhan */ public class DefaultJackson2JavaTypeMapper extends AbstractJavaTypeMapper implements Jackson2JavaTypeMapper { @@ -45,7 +46,7 @@ public class DefaultJackson2JavaTypeMapper extends AbstractJavaTypeMapper implem "java.lang" ); - private final Set trustedPackages = new LinkedHashSet(TRUSTED_PACKAGES); + private final Set trustedPackages = new LinkedHashSet<>(TRUSTED_PACKAGES); private volatile TypePrecedence typePrecedence = TypePrecedence.INFERRED; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java index e3e247f943..9474d1b7c8 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,11 +30,12 @@ * * @author Gary Russell * @author David Diehl + * @author Ngoc Nhan * @since 1.4.2 */ public class DelegatingDecompressingPostProcessor implements MessagePostProcessor, Ordered { - private final Map decompressors = new HashMap(); + private final Map decompressors = new HashMap<>(); private int order; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/MessagePostProcessorUtils.java b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/MessagePostProcessorUtils.java index bf2ed742d8..2c7a8f8b05 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/MessagePostProcessorUtils.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/MessagePostProcessorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,15 +29,16 @@ * Utilities for message post processors. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.4.2 * */ public final class MessagePostProcessorUtils { public static Collection sort(Collection processors) { - List priorityOrdered = new ArrayList(); - List ordered = new ArrayList(); - List unOrdered = new ArrayList(); + List priorityOrdered = new ArrayList<>(); + List ordered = new ArrayList<>(); + List unOrdered = new ArrayList<>(); for (MessagePostProcessor processor : processors) { if (processor instanceof PriorityOrdered) { priorityOrdered.add(processor); @@ -49,7 +50,7 @@ else if (processor instanceof Ordered) { unOrdered.add(processor); } } - List sorted = new ArrayList(); + List sorted = new ArrayList<>(); OrderComparator.sort(priorityOrdered); sorted.addAll(priorityOrdered); OrderComparator.sort(ordered); diff --git a/spring-amqp/src/main/java/org/springframework/amqp/utils/MapBuilder.java b/spring-amqp/src/main/java/org/springframework/amqp/utils/MapBuilder.java index 1fea0e2d65..e3afc18117 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/utils/MapBuilder.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/utils/MapBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2016-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,11 +26,12 @@ * @param the value type. * @author Artem Bilan * @author Gary Russell + * @author Ngoc Nhan * @since 2.0 */ public class MapBuilder, K, V> { - private final Map map = new HashMap(); + private final Map map = new HashMap<>(); public B put(K key, V value) { this.map.put(key, value); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/AsyncRabbitTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/AsyncRabbitTemplate.java index 077eacb7de..5bc5f44c89 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/AsyncRabbitTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/AsyncRabbitTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,6 +88,7 @@ * @author Gary Russell * @author Artem Bilan * @author FengYang Su + * @author Ngoc Nhan * * @since 1.6 */ @@ -482,7 +483,7 @@ public RabbitConverterFuture convertSendAndReceiveAsType(String exchange, private RabbitConverterFuture convertSendAndReceive(String exchange, String routingKey, Object object, MessagePostProcessor messagePostProcessor, ParameterizedTypeReference responseType) { - AsyncCorrelationData correlationData = new AsyncCorrelationData(messagePostProcessor, responseType, + AsyncCorrelationData correlationData = new AsyncCorrelationData<>(messagePostProcessor, responseType, this.enableConfirms); if (this.container != null) { this.template.convertAndSend(exchange, routingKey, object, this.messagePostProcessor, correlationData); @@ -731,7 +732,7 @@ public Message postProcessMessage(Message message, Correlation correlation) thro messageToSend = correlationData.userPostProcessor.postProcessMessage(message); } String correlationId = getOrSetCorrelationIdAndSetReplyTo(messageToSend, correlationData); - correlationData.future = new RabbitConverterFuture(correlationId, message, + correlationData.future = new RabbitConverterFuture<>(correlationId, message, AsyncRabbitTemplate.this::canceler, AsyncRabbitTemplate.this::timeoutTask); if (correlationData.enableConfirms) { correlationData.setId(correlationId); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java index 6946bb28e8..40f01b38bc 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java @@ -364,7 +364,7 @@ else if (source instanceof Method method) { private void processMultiMethodListeners(RabbitListener[] classLevelListeners, Method[] multiMethods, Object bean, String beanName) { - List checkedMethods = new ArrayList(); + List checkedMethods = new ArrayList<>(); Method defaultMethod = null; for (Method method : multiMethods) { Method checked = checkProxy(method, bean); @@ -734,7 +734,7 @@ else if (resolvedValueToUse instanceof Iterable) { } private String[] registerBeansForDeclaration(RabbitListener rabbitListener, Collection declarables) { - List queues = new ArrayList(); + List queues = new ArrayList<>(); if (this.beanFactory instanceof ConfigurableBeanFactory) { for (QueueBinding binding : rabbitListener.bindings()) { String queueName = declareQueue(binding.value(), declarables); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java index d1558f7a10..8958cac06c 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ * length field. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.4.1 * */ @@ -50,7 +51,7 @@ public class SimpleBatchingStrategy implements BatchingStrategy { private final long timeout; - private final List messages = new ArrayList(); + private final List messages = new ArrayList<>(); private String exchange; diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractExchangeParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractExchangeParser.java index 705fd84056..434e57d676 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractExchangeParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractExchangeParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ * @author Gary Russell * @author Felipe Gutierrez * @author Artem Bilan + * @author Ngoc Nhan * */ public abstract class AbstractExchangeParser extends AbstractSingleBeanDefinitionParser { @@ -144,7 +145,7 @@ private void parseArguments(Element element, String argumentsElementName, Parser Map map = parserContext.getDelegate().parseMapElement(argumentsElement, builder.getRawBeanDefinition()); if (StringUtils.hasText(ref)) { - if (map != null && map.size() > 0) { + if (map != null && !map.isEmpty()) { parserContext.getReaderContext().error("You cannot have both a 'ref' and a nested map", element); } if (propertyName == null) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java index afdd5ada8a..d7b6dbd971 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ * @author Mark Pollack * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * */ public abstract class NamespaceUtils { @@ -249,7 +250,7 @@ public static void parseDeclarationControls(Element element, BeanDefinitionBuild String admins = element.getAttribute("declared-by"); if (StringUtils.hasText(admins)) { String[] adminBeanNames = admins.split(","); - ManagedList adminBeanRefs = new ManagedList(); + ManagedList adminBeanRefs = new ManagedList<>(); for (String adminBeanName : adminBeanNames) { adminBeanRefs.add(new RuntimeBeanReference(adminBeanName.trim())); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java index fdf057a34b..b4fed509e0 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,15 +36,16 @@ * @author Josh Chappelle * @author Gary Russell * @author Leonardo Ferreira + * @author Ngoc Nhan * @since 1.3 */ public abstract class AbstractRoutingConnectionFactory implements ConnectionFactory, RoutingConnectionFactory, InitializingBean, DisposableBean { private final Map targetConnectionFactories = - new ConcurrentHashMap(); + new ConcurrentHashMap<>(); - private final List connectionListeners = new ArrayList(); + private final List connectionListeners = new ArrayList<>(); private ConnectionFactory defaultTargetConnectionFactory; diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeChannelListener.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeChannelListener.java index 81c7dd532f..66399f31e4 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeChannelListener.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeChannelListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,11 +25,12 @@ /** * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * */ public class CompositeChannelListener implements ChannelListener { - private List delegates = new ArrayList(); + private List delegates = new ArrayList<>(); public void onCreate(Channel channel, boolean transactional) { for (ChannelListener delegate : this.delegates) { @@ -45,7 +46,7 @@ public void onShutDown(ShutdownSignalException signal) { } public void setDelegates(List delegates) { - this.delegates = new ArrayList(delegates); + this.delegates = new ArrayList<>(delegates); } public void addDelegate(ChannelListener delegate) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java index ce1b01a7b2..0c9900cd77 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,11 +27,12 @@ * * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * */ public class CompositeConnectionListener implements ConnectionListener { - private List delegates = new CopyOnWriteArrayList(); + private List delegates = new CopyOnWriteArrayList<>(); @Override public void onCreate(Connection connection) { @@ -54,7 +55,7 @@ public void onFailed(Exception exception) { } public void setDelegates(List delegates) { - this.delegates = new ArrayList(delegates); + this.delegates = new ArrayList<>(delegates); } public void addDelegate(ConnectionListener delegate) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java index 0aac6947b3..d1a82f4d87 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ * tangle with RabbitResourceHolder. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.2 * */ @@ -39,7 +40,7 @@ public final class ConsumerChannelRegistry { private static final Log logger = LogFactory.getLog(ConsumerChannelRegistry.class); // NOSONAR - lower case private static final ThreadLocal consumerChannel // NOSONAR - lower case - = new ThreadLocal(); + = new ThreadLocal<>(); private ConsumerChannelRegistry() { } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/LocalizedQueueConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/LocalizedQueueConnectionFactory.java index e84ed71190..c27986322b 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/LocalizedQueueConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/LocalizedQueueConnectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ * * @author Gary Russell * @author Christian Tzolov + * @author Ngoc Nhan * @since 1.2 */ public class LocalizedQueueConnectionFactory implements ConnectionFactory, RoutingConnectionFactory, DisposableBean, @@ -61,13 +62,13 @@ public class LocalizedQueueConnectionFactory implements ConnectionFactory, Routi private final Lock lock = new ReentrantLock(); - private final Map nodeFactories = new HashMap(); + private final Map nodeFactories = new HashMap<>(); private final ConnectionFactory defaultConnectionFactory; private final String[] adminUris; - private final Map nodeToAddress = new HashMap(); + private final Map nodeToAddress = new HashMap<>(); private final String vhost; diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java index c298c118a9..12284d5bca 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,7 @@ * @author Arnaud Cogoluègnes * @author Artem Bilan * @author Christian Tzolov + * @author Ngoc Nhan * * @since 1.0.1 * @@ -924,7 +925,7 @@ public Collection expire(Listener listener, long cutoffTime) { return Collections.emptyList(); } else { - List expired = new ArrayList(); + List expired = new ArrayList<>(); Iterator> iterator = pendingConfirmsForListener.entrySet().iterator(); while (iterator.hasNext()) { PendingConfirm pendingConfirm = iterator.next().getValue(); @@ -1025,7 +1026,7 @@ private void processMultipleAck(long seq, boolean ack) { */ Map involvedListeners = this.listenerForSeq.headMap(seq + 1); // eliminate duplicates - Set listenersForAcks = new HashSet(involvedListeners.values()); + Set listenersForAcks = new HashSet<>(involvedListeners.values()); for (Listener involvedListener : listenersForAcks) { // find all unack'd confirms for this listener and handle them SortedMap confirmsMap = this.pendingConfirms.get(involvedListener); @@ -1047,7 +1048,7 @@ private void processMultipleAck(long seq, boolean ack) { } } } - List seqs = new ArrayList(involvedListeners.keySet()); + List seqs = new ArrayList<>(involvedListeners.keySet()); for (Long key : seqs) { this.listenerForSeq.remove(key); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitResourceHolder.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitResourceHolder.java index 8cea93e04e..80fd02e75a 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitResourceHolder.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitResourceHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ * @author Mark Fisher * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * * @see org.springframework.amqp.rabbit.transaction.RabbitTransactionManager * @see org.springframework.amqp.rabbit.core.RabbitTemplate @@ -120,7 +121,7 @@ public final void addChannel(Channel channel, @Nullable Connection connection) { if (connection != null) { List channelsForConnection = this.channelsPerConnection.get(connection); if (channelsForConnection == null) { - channelsForConnection = new LinkedList(); + channelsForConnection = new LinkedList<>(); this.channelsPerConnection.put(connection, channelsForConnection); } channelsForConnection.add(channel); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java index bacdf4a61f..f0861a0497 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ * * @author Artem Bilan * @author Gary Russell + * @author Ngoc Nhan * @since 1.3 */ public final class SimpleResourceHolder { @@ -56,10 +57,10 @@ public final class SimpleResourceHolder { private static final Log LOGGER = LogFactory.getLog(SimpleResourceHolder.class); private static final ThreadLocal> RESOURCES = - new NamedThreadLocal>("Simple resources"); + new NamedThreadLocal<>("Simple resources"); private static final ThreadLocal>> STACK = - new NamedThreadLocal>>("Simple resources"); + new NamedThreadLocal<>("Simple resources"); /** * Return all resources that are bound to the current thread. @@ -126,7 +127,7 @@ public static void bind(Object key, Object value) { Map map = RESOURCES.get(); // set ThreadLocal Map if none found if (map == null) { - map = new HashMap(); + map = new HashMap<>(); RESOURCES.set(map); } Object oldValue = map.put(key, value); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java index a4031e88dc..7ea93712fe 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ * @author Stephane Nicoll * @author Gary Russell * @author Artem Bilan + * @author Ngoc Nhan * * @since 1.4 * @@ -298,7 +299,7 @@ public void setTaskExecutor(TaskExecutor taskExecutor) { * @return true if batch. */ public boolean isBatchListener() { - return this.batchListener == null ? false : this.batchListener; + return this.batchListener != null && this.batchListener; } @Override diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/ConditionalRejectingErrorHandler.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/ConditionalRejectingErrorHandler.java index acd7cbedb8..33204d1b64 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/ConditionalRejectingErrorHandler.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/ConditionalRejectingErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,6 +50,7 @@ * {@link AmqpRejectAndDontRequeueException}. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.3.2 * */ @@ -136,7 +137,7 @@ public void handleError(Throwable t) { Message failed = lefe.getFailedMessage(); if (failed != null) { List> xDeath = failed.getMessageProperties().getXDeathHeader(); - if (xDeath != null && xDeath.size() > 0) { + if (xDeath != null && !xDeath.isEmpty()) { this.logger.error("x-death header detected on a message with a fatal exception; " + "perhaps requeued from a DLQ? - discarding: " + failed); handleDiscarded(failed); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MultiMethodRabbitListenerEndpoint.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MultiMethodRabbitListenerEndpoint.java index 2f5ebbd865..1833eee771 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MultiMethodRabbitListenerEndpoint.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MultiMethodRabbitListenerEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ /** * @author Gary Russell + * @author Ngoc Nhan * @since 1.5 * */ @@ -64,7 +65,7 @@ public void setValidator(Validator validator) { @Override protected HandlerAdapter configureListenerAdapter(MessagingMessageListenerAdapter messageListener) { - List invocableHandlerMethods = new ArrayList(); + List invocableHandlerMethods = new ArrayList<>(); InvocableHandlerMethod defaultHandler = null; for (Method method : this.methods) { InvocableHandlerMethod handler = getMessageHandlerMethodFactory() diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/ActiveObjectCounter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/ActiveObjectCounter.java index 30abbced57..e37a5653be 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/ActiveObjectCounter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/ActiveObjectCounter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,11 +29,12 @@ * * @author Dave Syer * @author Artem Bilan + * @author Ngoc Nhan * */ public class ActiveObjectCounter { - private final ConcurrentMap locks = new ConcurrentHashMap(); + private final ConcurrentMap locks = new ConcurrentHashMap<>(); private volatile boolean active = true; @@ -56,7 +57,7 @@ public boolean await(long timeout, TimeUnit timeUnit) throws InterruptedExceptio if (this.locks.isEmpty()) { return true; } - Collection objects = new HashSet(this.locks.keySet()); + Collection objects = new HashSet<>(this.locks.keySet()); for (T object : objects) { CountDownLatch lock = this.locks.get(object); if (lock == null) { From 7a303554ea196dee203dcc50b53c1b153a2aaecc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 03:02:36 +0000 Subject: [PATCH 025/111] Bump com.github.spotbugs in the development-dependencies group (#2843) Bumps the development-dependencies group with 1 update: com.github.spotbugs. Updates `com.github.spotbugs` from 6.0.22 to 6.0.23 --- updated-dependencies: - dependency-name: com.github.spotbugs dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 284c3366ec..efb4b10277 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' - id 'com.github.spotbugs' version '6.0.22' + id 'com.github.spotbugs' version '6.0.23' id 'io.freefair.aggregate-javadoc' version '8.6' } From ba404b26330d0a870322b08a43ea27108fda0e38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 03:02:44 +0000 Subject: [PATCH 026/111] Bump com.github.luben:zstd-jni from 1.5.6-5 to 1.5.6-6 (#2844) Bumps [com.github.luben:zstd-jni](https://github.com/luben/zstd-jni) from 1.5.6-5 to 1.5.6-6. - [Commits](https://github.com/luben/zstd-jni/compare/v1.5.6-5...v1.5.6-6) --- updated-dependencies: - dependency-name: com.github.luben:zstd-jni dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index efb4b10277..3d946dc637 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ ext { springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.20.1' - zstdJniVersion = '1.5.6-5' + zstdJniVersion = '1.5.6-6' javaProjects = subprojects - project(':spring-amqp-bom') } From ce9c67ca9396a4bcbf96b94ad546cf55e5d4474d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 03:02:52 +0000 Subject: [PATCH 027/111] Bump org.junit:junit-bom from 5.11.0 to 5.11.1 (#2845) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.0 to 5.11.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3d946dc637..048fa0ce0d 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ ext { jacksonBomVersion = '2.17.2' jaywayJsonPathVersion = '2.9.0' junit4Version = '4.13.2' - junitJupiterVersion = '5.11.0' + junitJupiterVersion = '5.11.1' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.0' logbackVersion = '1.5.8' From a597c1574d9b3777160cd11ea3d34eda7c10d87d Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 30 Sep 2024 20:41:46 +0700 Subject: [PATCH 028/111] Modernize more code for diamond, isEmpty & pattern matching --- .../amqp/core/BindingBuilder.java | 2 +- .../listener/StreamListenerContainer.java | 7 ++-- .../DefaultStreamMessageConverter.java | 3 +- ...itListenerAnnotationBeanPostProcessor.java | 6 ++-- .../rabbit/batch/SimpleBatchingStrategy.java | 6 ++-- .../rabbit/config/HeadersExchangeParser.java | 5 +-- .../config/ListenerContainerFactoryBean.java | 3 +- .../config/ListenerContainerParser.java | 9 +++--- .../amqp/rabbit/config/QueueParser.java | 5 +-- .../rabbit/config/RabbitNamespaceUtils.java | 32 ++++++++----------- .../amqp/rabbit/config/TemplateParser.java | 3 +- .../PublisherCallbackChannelImpl.java | 4 +-- .../connection/SimpleResourceHolder.java | 2 +- .../ThreadChannelConnectionFactory.java | 5 +-- .../rabbit/core/BatchingRabbitTemplate.java | 4 +-- .../AbstractRabbitListenerEndpoint.java | 3 +- .../adapter/MessageListenerAdapter.java | 7 ++-- .../retry/RepublishMessageRecoverer.java | 4 +-- 18 files changed, 56 insertions(+), 54 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java index 956d83d8ec..5eceadd960 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java @@ -82,7 +82,7 @@ public static final class DestinationConfigurer { } public Binding to(FanoutExchange exchange) { - return new Binding(this.queue, this.name, this.type, exchange.getName(), "", new HashMap()); + return new Binding(this.queue, this.name, this.type, exchange.getName(), "", new HashMap<>()); } public HeadersExchangeMapConfigurer to(HeadersExchange exchange) { diff --git a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/listener/StreamListenerContainer.java b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/listener/StreamListenerContainer.java index 925565cb29..842ca8f071 100644 --- a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/listener/StreamListenerContainer.java +++ b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/listener/StreamListenerContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 the original author or authors. + * Copyright 2021-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +56,7 @@ * * @author Gary Russell * @author Christian Tzolov + * @author Ngoc Nhan * @since 2.4 * */ @@ -251,7 +252,7 @@ public void afterPropertiesSet() { public boolean isRunning() { this.lock.lock(); try { - return this.consumers.size() > 0; + return !this.consumers.isEmpty(); } finally { this.lock.unlock(); @@ -262,7 +263,7 @@ public boolean isRunning() { public void start() { this.lock.lock(); try { - if (this.consumers.size() == 0) { + if (this.consumers.isEmpty()) { this.consumerCustomizer.accept(getListenerId(), this.builder); if (this.simpleStream) { this.consumers.add(this.builder.build()); diff --git a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/support/converter/DefaultStreamMessageConverter.java b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/support/converter/DefaultStreamMessageConverter.java index dd2d765fd7..614f4a6e79 100644 --- a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/support/converter/DefaultStreamMessageConverter.java +++ b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/support/converter/DefaultStreamMessageConverter.java @@ -41,6 +41,7 @@ * Default {@link StreamMessageConverter}. * * @author Gary Russell + * @author Ngoc Nhan * @since 2.4 * */ @@ -105,7 +106,7 @@ public com.rabbitmq.stream.Message fromMessage(Message message) throws MessageCo .acceptIfNotNull(mProps.getGroupSequence(), propsBuilder::groupSequence) .acceptIfNotNull(mProps.getReplyToGroupId(), propsBuilder::replyToGroupId); ApplicationPropertiesBuilder appPropsBuilder = builder.applicationProperties(); - if (mProps.getHeaders().size() > 0) { + if (!mProps.getHeaders().isEmpty()) { mProps.getHeaders().forEach((key, val) -> { mapProp(key, val, appPropsBuilder); }); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java index 40f01b38bc..2c1ce24447 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java @@ -317,12 +317,12 @@ public Object postProcessAfterInitialization(final Object bean, final String bea private TypeMetadata buildMetadata(Class targetClass) { List classLevelListeners = findListenerAnnotations(targetClass); - final boolean hasClassLevelListeners = classLevelListeners.size() > 0; + final boolean hasClassLevelListeners = !classLevelListeners.isEmpty(); final List methods = new ArrayList<>(); final List multiMethods = new ArrayList<>(); ReflectionUtils.doWithMethods(targetClass, method -> { List listenerAnnotations = findListenerAnnotations(method); - if (listenerAnnotations.size() > 0) { + if (!listenerAnnotations.isEmpty()) { methods.add(new ListenerMethod(method, listenerAnnotations.toArray(new RabbitListener[listenerAnnotations.size()]))); } @@ -880,7 +880,7 @@ private Map resolveArguments(Argument[] arguments) { } } } - return map.size() < 1 ? null : map; + return map.isEmpty() ? null : map; } private void addToMap(Map map, String key, Object value, Class typeClass, String typeName) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java index 8958cac06c..a7f80b3d46 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/batch/SimpleBatchingStrategy.java @@ -88,7 +88,7 @@ public MessageBatch addToBatch(String exch, String routKey, Message message) { } int bufferUse = Integer.BYTES + message.getBody().length; MessageBatch batch = null; - if (this.messages.size() > 0 && this.currentSize + bufferUse > this.bufferLimit) { + if (!this.messages.isEmpty() && this.currentSize + bufferUse > this.bufferLimit) { batch = doReleaseBatch(); this.exchange = exch; this.routingKey = routKey; @@ -104,7 +104,7 @@ public MessageBatch addToBatch(String exch, String routKey, Message message) { @Override public Date nextRelease() { - if (this.messages.size() == 0 || this.timeout <= 0) { + if (this.messages.isEmpty() || this.timeout <= 0) { return null; } else if (this.currentSize >= this.bufferLimit) { @@ -128,7 +128,7 @@ public Collection releaseBatches() { } private MessageBatch doReleaseBatch() { - if (this.messages.size() < 1) { + if (this.messages.isEmpty()) { return null; } Message message = assembleMessage(); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/HeadersExchangeParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/HeadersExchangeParser.java index fc38d35a90..0cb49dbab2 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/HeadersExchangeParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/HeadersExchangeParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ * @author Dave Syer * @author Gary Russell * @author Artem Bilan + * @author Ngoc Nhan * */ public class HeadersExchangeParser extends AbstractExchangeParser { @@ -63,7 +64,7 @@ protected BeanDefinitionBuilder parseBinding(String exchangeName, Element bindin parserContext.getReaderContext() .error("At least one of 'binding-arguments' sub-element or 'key/value' attributes pair have to be declared.", binding); } - ManagedMap map = new ManagedMap(); + ManagedMap map = new ManagedMap<>(); map.put(new TypedStringValue(key), new TypedStringValue(value)); builder.addPropertyValue("arguments", map); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java index 0a070e1eca..c919105ea1 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java @@ -56,6 +56,7 @@ * @author Artem Bilan * @author Johno Crawford * @author Jeonggi Kim + * @author Ngoc Nhan * * @since 2.0 * @@ -542,7 +543,7 @@ protected AbstractMessageListenerContainer createInstance() { // NOSONAR complex .acceptIfNotNull(this.exclusiveConsumerExceptionLogger, container::setExclusiveConsumerExceptionLogger) .acceptIfNotNull(this.micrometerEnabled, container::setMicrometerEnabled) - .acceptIfCondition(this.micrometerTags.size() > 0, this.micrometerTags, + .acceptIfCondition(!this.micrometerTags.isEmpty(), this.micrometerTags, container::setMicrometerTags); if (this.smlcCustomizer != null && this.type.equals(Type.simple)) { this.smlcCustomizer.configure((SimpleMessageListenerContainer) container); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java index 0fb64b643c..fce31f9935 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ /** * @author Mark Fisher * @author Gary Russell + * @author Ngoc Nhan * @since 1.0 */ class ListenerContainerParser implements BeanDefinitionParser { @@ -188,7 +189,7 @@ private void parseListener(Element listenerEle, Element containerEle, ParserCont } else { String[] names = StringUtils.commaDelimitedListToStringArray(queues); - List values = new ManagedList(); + List values = new ManagedList<>(); for (int i = 0; i < names.length; i++) { values.add(new RuntimeBeanReference(names[i].trim())); } @@ -196,14 +197,14 @@ private void parseListener(Element listenerEle, Element containerEle, ParserCont } } - ManagedMap args = new ManagedMap(); + ManagedMap args = new ManagedMap<>(); String priority = listenerEle.getAttribute("priority"); if (StringUtils.hasText(priority)) { args.put("x-priority", new TypedStringValue(priority, Integer.class)); } - if (args.size() > 0) { + if (!args.isEmpty()) { containerDef.getPropertyValues().add("consumerArguments", args); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/QueueParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/QueueParser.java index 4bce257e1a..38314dad06 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/QueueParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/QueueParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ * @author Gary Russell * @author Felipe Gutierrez * @author Artem Bilan + * @author Ngoc Nhan * */ public class QueueParser extends AbstractSingleBeanDefinitionParser { @@ -134,7 +135,7 @@ private void parseArguments(Element element, ParserContext parserContext, BeanDe Map map = parserContext.getDelegate().parseMapElement(argumentsElement, builder.getRawBeanDefinition()); if (StringUtils.hasText(ref)) { - if (map != null && map.size() > 0) { + if (map != null && !map.isEmpty()) { parserContext.getReaderContext() .error("You cannot have both a 'ref' and a nested map", element); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/RabbitNamespaceUtils.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/RabbitNamespaceUtils.java index 69ba403406..c219c7bf7c 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/RabbitNamespaceUtils.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/RabbitNamespaceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -358,28 +358,22 @@ public static BeanDefinition parseContainer(Element containerEle, ParserContext } private static AcknowledgeMode parseAcknowledgeMode(Element ele, ParserContext parserContext) { - AcknowledgeMode acknowledgeMode = null; String acknowledge = ele.getAttribute(ACKNOWLEDGE_ATTRIBUTE); if (StringUtils.hasText(acknowledge)) { - if (ACKNOWLEDGE_AUTO.equals(acknowledge)) { - acknowledgeMode = AcknowledgeMode.AUTO; - } - else if (ACKNOWLEDGE_MANUAL.equals(acknowledge)) { - acknowledgeMode = AcknowledgeMode.MANUAL; - } - else if (ACKNOWLEDGE_NONE.equals(acknowledge)) { - acknowledgeMode = AcknowledgeMode.NONE; - } - else { - parserContext.getReaderContext().error( + return switch (acknowledge) { + case ACKNOWLEDGE_AUTO -> AcknowledgeMode.AUTO; + case ACKNOWLEDGE_MANUAL -> AcknowledgeMode.MANUAL; + case ACKNOWLEDGE_NONE -> AcknowledgeMode.NONE; + default -> { + parserContext.getReaderContext().error( "Invalid listener container 'acknowledge' setting [" + acknowledge - + "]: only \"auto\", \"manual\", and \"none\" supported.", ele); - } - return acknowledgeMode; - } - else { - return null; + + "]: only \"auto\", \"manual\", and \"none\" supported.", ele); + yield null; + } + }; } + + return null; } } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/TemplateParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/TemplateParser.java index 5259fa0e25..c9c5c3f908 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/TemplateParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/TemplateParser.java @@ -34,6 +34,7 @@ * @author Dave Syer * @author Gary Russell * @author Artem Bilan + * @author Ngoc Nhan */ class TemplateParser extends AbstractSingleBeanDefinitionParser { @@ -160,7 +161,7 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit BeanDefinition replyContainer = null; Element childElement = null; List childElements = DomUtils.getChildElementsByTagName(element, LISTENER_ELEMENT); - if (childElements.size() > 0) { + if (!childElements.isEmpty()) { childElement = childElements.get(0); } if (childElement != null) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java index 12284d5bca..b8ee5e29dd 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java @@ -904,12 +904,12 @@ public int getPendingConfirmsCount() { @Override public void addListener(Listener listener) { Assert.notNull(listener, "Listener cannot be null"); - if (this.listeners.size() == 0) { + if (this.listeners.isEmpty()) { this.delegate.addConfirmListener(this); this.delegate.addReturnListener(this); } if (this.listeners.putIfAbsent(listener.getUUID(), listener) == null) { - this.pendingConfirms.put(listener, new ConcurrentSkipListMap()); + this.pendingConfirms.put(listener, new ConcurrentSkipListMap<>()); if (this.logger.isDebugEnabled()) { this.logger.debug("Added listener " + listener); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java index f0861a0497..10036d3ad2 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/SimpleResourceHolder.java @@ -176,7 +176,7 @@ public static Object pop(Object key) { Map> stack = STACK.get(); if (stack != null) { Deque deque = stack.get(key); - if (deque != null && deque.size() > 0) { + if (deque != null && !deque.isEmpty()) { Object previousValue = deque.pop(); if (previousValue != null) { bind(key, previousValue); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java index d1b667532f..b9d371e683 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ * @author Gary Russell * @author Leonardo Ferreira * @author Christian Tzolov + * @author Ngoc Nhan * @since 2.3 * */ @@ -191,7 +192,7 @@ public void destroy() { this.connection.forceClose(); this.connection = null; } - if (this.switchesInProgress.size() > 0 && this.logger.isWarnEnabled()) { + if (!this.switchesInProgress.isEmpty() && this.logger.isWarnEnabled()) { this.logger.warn("Unclaimed context switches from threads:" + this.switchesInProgress.values() .stream() diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplate.java index 8982d80986..18e0b11719 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,7 +99,7 @@ public void send(String exchange, String routingKey, Message message, } Date next = this.batchingStrategy.nextRelease(); if (next != null) { - this.scheduledTask = this.scheduler.schedule((Runnable) () -> releaseBatches(), next.toInstant()); + this.scheduledTask = this.scheduler.schedule(this::releaseBatches, next.toInstant()); } } } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java index 7ea93712fe..de0a38f538 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java @@ -397,8 +397,7 @@ public void setupListenerContainer(MessageListenerContainer listenerContainer) { throw new IllegalStateException("Queues or queue names must be provided but not both for " + this); } if (queuesEmpty) { - Collection names = qNames; - container.setQueueNames(names.toArray(new String[0])); + container.setQueueNames(qNames.toArray(new String[0])); } else { Collection instances = getQueues(); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java index c9c90a1871..65667d8453 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -118,6 +118,7 @@ * @author Gary Russell * @author Greg Turnquist * @author Cai Kun + * @author Ngoc Nhan * * @see #setDelegate * @see #setDefaultListenerMethod @@ -129,7 +130,7 @@ */ public class MessageListenerAdapter extends AbstractAdaptableMessageListener { - private final Map queueOrTagToMethodName = new HashMap(); + private final Map queueOrTagToMethodName = new HashMap<>(); /** * Out-of-the-box value for the default listener method: "handleMessage". @@ -314,7 +315,7 @@ else if (delegateListener instanceof MessageListener messageListener) { * @see #setQueueOrTagToMethodName */ protected String getListenerMethodName(Message originalMessage, Object extractedMessage) { - if (this.queueOrTagToMethodName.size() > 0) { + if (!this.queueOrTagToMethodName.isEmpty()) { MessageProperties props = originalMessage.getMessageProperties(); String methodName = this.queueOrTagToMethodName.get(props.getConsumerQueue()); if (methodName == null) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/retry/RepublishMessageRecoverer.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/retry/RepublishMessageRecoverer.java index ae84767aa3..61bb2122c7 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/retry/RepublishMessageRecoverer.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/retry/RepublishMessageRecoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,7 +91,7 @@ public class RepublishMessageRecoverer implements MessageRecoverer { * @param errorTemplate the template. */ public RepublishMessageRecoverer(AmqpTemplate errorTemplate) { - this(errorTemplate, (String) null, (String) null); + this(errorTemplate, null, (String) null); } /** From cbc2eb386b8bd185793f408e9f9c18370dd9de18 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 1 Oct 2024 17:32:36 -0400 Subject: [PATCH 029/111] Upgrade to Jackson 2.18 * Fix `ObservationTests` for the latest changes with default tags. Related to: https://github.com/spring-projects/spring-amqp/issues/2814 --- build.gradle | 2 +- .../rabbit/support/micrometer/ObservationTests.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 048fa0ce0d..0f5fd35186 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,7 @@ ext { commonsPoolVersion = '2.12.0' hamcrestVersion = '2.2' hibernateValidationVersion = '8.0.1.Final' - jacksonBomVersion = '2.17.2' + jacksonBomVersion = '2.18.0' jaywayJsonPathVersion = '2.9.0' junit4Version = '4.13.2' junitJupiterVersion = '5.11.1' diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java index 4c0b6fa056..fe1b38995a 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java @@ -67,6 +67,8 @@ /** * @author Gary Russell * @author Ngoc Nhan + * @author Artem Bilan + * * @since 3.0 * */ @@ -91,17 +93,17 @@ void endToEnd(@Autowired Listener listener, @Autowired RabbitTemplate template, SimpleSpan span = spans.poll(); assertThat(span.getTags()).containsEntry("spring.rabbit.template.name", "template"); assertThat(span.getName()).isEqualTo("/observation.testQ1 send"); - await().until(() -> spans.peekFirst().getTags().size() == 3); + await().until(() -> spans.peekFirst().getTags().size() == 5); span = spans.poll(); assertThat(span.getTags()) .containsAllEntriesOf( Map.of("spring.rabbit.listener.id", "obs1", "foo", "some foo value", "bar", "some bar value")); assertThat(span.getName()).isEqualTo("observation.testQ1 receive"); - await().until(() -> spans.peekFirst().getTags().size() == 1); + await().until(() -> spans.peekFirst().getTags().size() == 3); span = spans.poll(); assertThat(span.getTags()).containsEntry("spring.rabbit.template.name", "template"); assertThat(span.getName()).isEqualTo("/observation.testQ2 send"); - await().until(() -> spans.peekFirst().getTags().size() == 3); + await().until(() -> spans.peekFirst().getTags().size() == 5); span = spans.poll(); assertThat(span.getTags()) .containsAllEntriesOf( @@ -141,7 +143,7 @@ public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context assertThat(span.getTags()).containsEntry("messaging.destination.name", ""); assertThat(span.getTags()).containsEntry("messaging.rabbitmq.destination.routing_key", "observation.testQ1"); assertThat(span.getName()).isEqualTo("/observation.testQ1 send"); - await().until(() -> spans.peekFirst().getTags().size() == 4); + await().until(() -> spans.peekFirst().getTags().size() == 6); span = spans.poll(); assertThat(span.getTags()) .containsAllEntriesOf(Map.of("spring.rabbit.listener.id", "obs1", "foo", "some foo value", "bar", @@ -154,7 +156,7 @@ public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context assertThat(span.getTags()).containsEntry("messaging.destination.name", ""); assertThat(span.getTags()).containsEntry("messaging.rabbitmq.destination.routing_key", "observation.testQ2"); assertThat(span.getName()).isEqualTo("/observation.testQ2 send"); - await().until(() -> spans.peekFirst().getTags().size() == 3); + await().until(() -> spans.peekFirst().getTags().size() == 5); span = spans.poll(); assertThat(span.getTags()) .containsAllEntriesOf( From 47868257e03b1c09e8cb5d08506655a5989e2363 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 2 Oct 2024 12:16:10 -0400 Subject: [PATCH 030/111] Attempt to use `services:rabbitmq` for `ci-snapshot.yml` Since we cannot propagate `services` down to the reusable workflow, we don't have choice, but build respective job ourselves --- .github/workflows/ci-snapshot.yml | 39 ++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index a21192cd2c..d7efae0383 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -17,10 +17,37 @@ concurrency: jobs: build-snapshot: - uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-snapshot.yml@main - with: - gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} - secrets: + runs-on: ubuntu-latest + name: CI Build SNAPSHOT for ${{ github.ref_name }} + env: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} - ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} \ No newline at end of file + + services: + rabbitmq: + image: rabbitmq:3.13.7-management + options: --name rabbitmq + ports: + - 5672:5672 + - 15672:15672 + - 5552:5552 + + steps: + - run: docker exec rabbitmq rabbitmq-plugins enable rabbitmq_stream + - uses: actions/checkout@v4 + with: + show-progress: false + + - name: Checkout Common Repo + uses: actions/checkout@v4 + with: + repository: spring-io/spring-github-workflows + path: spring-github-workflows + show-progress: false + + - name: Build and Publish + timeout-minutes: 30 + uses: ./spring-github-workflows/.github/actions/spring-artifactory-gradle-build + with: + gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} + artifactoryUsername: ${{ secrets.ARTIFACTORY_USERNAME }} + artifactoryPassword: ${{ secrets.ARTIFACTORY_PASSWORD }} From e8b4618397d89b3f54f056a1d678df15c6ee53b6 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 2 Oct 2024 12:21:26 -0400 Subject: [PATCH 031/111] Test `ci-snapshot.yml` without Gradle cache --- .github/workflows/ci-snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index d7efae0383..ba43d17b32 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -48,6 +48,6 @@ jobs: timeout-minutes: 30 uses: ./spring-github-workflows/.github/actions/spring-artifactory-gradle-build with: - gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} + gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '--rerun-tasks' }} artifactoryUsername: ${{ secrets.ARTIFACTORY_USERNAME }} artifactoryPassword: ${{ secrets.ARTIFACTORY_PASSWORD }} From 0223c1cffa42345ac53c6ae5ba5d4427d596630a Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 2 Oct 2024 12:31:47 -0400 Subject: [PATCH 032/111] The `services:rabbitmq` does not work well somehow --- .github/workflows/ci-snapshot.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index ba43d17b32..116110e66d 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -22,17 +22,13 @@ jobs: env: DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - services: - rabbitmq: - image: rabbitmq:3.13.7-management - options: --name rabbitmq - ports: - - 5672:5672 - - 15672:15672 - - 5552:5552 - steps: - - run: docker exec rabbitmq rabbitmq-plugins enable rabbitmq_stream + - name: Start RabbitMQ + uses: namoshek/rabbitmq-github-action@v1 + with: + ports: '5672:5672 15672:15672 5552:5552' + plugins: rabbitmq_stream,rabbitmq_management + - uses: actions/checkout@v4 with: show-progress: false From 966b29f1fe846d20f6f2e22b6d8e131f3b0e7b5b Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 2 Oct 2024 12:41:12 -0400 Subject: [PATCH 033/111] Add more plugins to RabbitMQ action for `ci-snapshot.yml` --- .github/workflows/ci-snapshot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-snapshot.yml b/.github/workflows/ci-snapshot.yml index 116110e66d..37070bd9c2 100644 --- a/.github/workflows/ci-snapshot.yml +++ b/.github/workflows/ci-snapshot.yml @@ -27,7 +27,7 @@ jobs: uses: namoshek/rabbitmq-github-action@v1 with: ports: '5672:5672 15672:15672 5552:5552' - plugins: rabbitmq_stream,rabbitmq_management + plugins: rabbitmq_stream,rabbitmq_management,rabbitmq_delayed_message_exchange,rabbitmq_consistent_hash_exchange - uses: actions/checkout@v4 with: @@ -44,6 +44,6 @@ jobs: timeout-minutes: 30 uses: ./spring-github-workflows/.github/actions/spring-artifactory-gradle-build with: - gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '--rerun-tasks' }} + gradleTasks: ${{ github.event_name == 'schedule' && '--rerun-tasks' || '' }} artifactoryUsername: ${{ secrets.ARTIFACTORY_USERNAME }} artifactoryPassword: ${{ secrets.ARTIFACTORY_PASSWORD }} From 949bf52a99a3ec041c51eb1ecc6a53540d9ef7b4 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 3 Oct 2024 14:10:16 -0400 Subject: [PATCH 034/111] Fix `RabbitUtils` for actual reason when cannot declare exchange **Auto-cherry-pick to `3.1.x`** --- .../springframework/amqp/rabbit/connection/RabbitUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java index 4a958f6529..1d0c1609f8 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java @@ -354,8 +354,8 @@ public static boolean isExchangeDeclarationFailure(Exception e) { } else { Method shutdownReason = sig.getReason(); - return shutdownReason instanceof AMQP.Connection.Close closeReason - && AMQP.COMMAND_INVALID == closeReason.getReplyCode() + return shutdownReason instanceof AMQP.Channel.Close closeReason + && AMQP.PRECONDITION_FAILED == closeReason.getReplyCode() && closeReason.getClassId() == EXCHANGE_CLASS_ID_40 && closeReason.getMethodId() == DECLARE_METHOD_ID_10; } From 82bed3f24efaaa4ecce7765abe232d7bb9811e07 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Oct 2024 10:08:25 -0400 Subject: [PATCH 035/111] Fix timing in the `AsyncRabbitTemplateTests` --- .../springframework/amqp/rabbit/AsyncRabbitTemplateTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java index 1c72c9db77..e054a7abab 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java @@ -473,7 +473,8 @@ private Message checkMessageResult(CompletableFuture future, String exp }); assertThat(cdl.await(10, TimeUnit.SECONDS)).isTrue(); assertThat(new String(resultRef.get().getBody())).isEqualTo(expected); - assertThat(TestUtils.getPropertyValue(future, "timeoutTask", Future.class).isCancelled()).isTrue(); + await().untilAsserted(() -> + assertThat(TestUtils.getPropertyValue(future, "timeoutTask", Future.class).isCancelled()).isTrue()); return resultRef.get(); } From b76b6195f58ab2d8b3ddc84493c2a140d0c64055 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Oct 2024 12:12:35 -0400 Subject: [PATCH 036/111] Fix race condition in the `EnableRabbitKotlinTests.kt` --- .../amqp/rabbit/annotation/EnableRabbitKotlinTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt b/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt index 87fe6dba34..4b94a657e6 100644 --- a/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt +++ b/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt @@ -105,8 +105,8 @@ class EnableRabbitKotlinTests { @RabbitListener(id = "batch", queues = ["kotlinBatchQueue"], containerFactory = "batchRabbitListenerContainerFactory") suspend fun receiveBatch(messages: List) { - batchReceived.countDown() batch = messages + batchReceived.countDown() } @Bean From cdf36cd38c5a1a7f2e7622be53acb2b0b6eba6ee Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Oct 2024 12:26:39 -0400 Subject: [PATCH 037/111] Fix race condition in the `MessageListenerContainerMultipleQueueIntegrationTests` --- ...ontainerMultipleQueueIntegrationTests.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java index 155eeaa885..9930f42929 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java @@ -16,8 +16,6 @@ package org.springframework.amqp.rabbit.listener; -import static org.assertj.core.api.Assertions.assertThat; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -36,15 +34,18 @@ import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.amqp.support.converter.SimpleMessageConverter; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Mark Fisher * @author Gunnar Hillert * @author Gary Russell + * @author Artem Bilan */ -@RabbitAvailable(queues = { MessageListenerContainerMultipleQueueIntegrationTests.TEST_QUEUE_1, - MessageListenerContainerMultipleQueueIntegrationTests.TEST_QUEUE_2 }) -@LogLevels(level = "INFO", classes = { RabbitTemplate.class, - SimpleMessageListenerContainer.class, BlockingQueueConsumer.class }) +@RabbitAvailable(queues = {MessageListenerContainerMultipleQueueIntegrationTests.TEST_QUEUE_1, + MessageListenerContainerMultipleQueueIntegrationTests.TEST_QUEUE_2}) +@LogLevels(level = "INFO", classes = {RabbitTemplate.class, + SimpleMessageListenerContainer.class, BlockingQueueConsumer.class}) public class MessageListenerContainerMultipleQueueIntegrationTests { public static final String TEST_QUEUE_1 = "test.queue.1.MessageListenerContainerMultipleQueueIntegrationTests"; @@ -77,7 +78,6 @@ public void testMultipleQueueNamesWithConcurrentConsumers() { doTest(3, container -> container.setQueueNames(queue1.getName(), queue2.getName())); } - private void doTest(int concurrentConsumers, ContainerConfigurer configurer) { int messageCount = 10; RabbitTemplate template = new RabbitTemplate(); @@ -119,17 +119,15 @@ private void doTest(int concurrentConsumers, ContainerConfigurer configurer) { container.shutdown(); assertThat(container.getActiveConsumerCount()).isEqualTo(0); } - assertThat(template.receiveAndConvert(queue1.getName())).isNull(); - assertThat(template.receiveAndConvert(queue2.getName())).isNull(); - connectionFactory.destroy(); } @FunctionalInterface private interface ContainerConfigurer { + void configure(SimpleMessageListenerContainer container); - } + } @SuppressWarnings("unused") private static class PojoListener { @@ -150,6 +148,7 @@ public void handleMessage(int value) throws Exception { public int getCount() { return count.get(); } + } } From 39d1325feb88d6f7aca954838335887c4c9a70cf Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Oct 2024 12:34:08 -0400 Subject: [PATCH 038/111] Fix Checkstyle violation for imports order --- ...MessageListenerContainerMultipleQueueIntegrationTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java index 9930f42929..d2fe778b84 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerMultipleQueueIntegrationTests.java @@ -16,6 +16,8 @@ package org.springframework.amqp.rabbit.listener; +import static org.assertj.core.api.Assertions.assertThat; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -34,8 +36,6 @@ import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.amqp.support.converter.SimpleMessageConverter; -import static org.assertj.core.api.Assertions.assertThat; - /** * @author Mark Fisher * @author Gunnar Hillert From 5b24690d44624f24a954298ea1c54a00b6add9db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:13:50 +0000 Subject: [PATCH 039/111] Bump the development-dependencies group with 2 updates (#2847) Bumps the development-dependencies group with 2 updates: com.github.spotbugs and [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions). Updates `com.github.spotbugs` from 6.0.23 to 6.0.24 Updates `io.spring.develocity.conventions` from 0.0.21 to 0.0.22 - [Release notes](https://github.com/spring-io/develocity-conventions/releases) - [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.21...v0.0.22) --- updated-dependencies: - dependency-name: com.github.spotbugs dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: io.spring.develocity.conventions dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- settings.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 0f5fd35186..3ced3a412f 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' - id 'com.github.spotbugs' version '6.0.23' + id 'com.github.spotbugs' version '6.0.24' id 'io.freefair.aggregate-javadoc' version '8.6' } diff --git a/settings.gradle b/settings.gradle index 87c12dd0fa..083f33a8a1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ pluginManagement { } plugins { - id 'io.spring.develocity.conventions' version '0.0.21' + id 'io.spring.develocity.conventions' version '0.0.22' } rootProject.name = 'spring-amqp-dist' From 5075525bcfa6cb4dd9ca30a6823b7228c88b06a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:14:03 +0000 Subject: [PATCH 040/111] Bump log4jVersion from 2.24.0 to 2.24.1 (#2849) Bumps `log4jVersion` from 2.24.0 to 2.24.1. Updates `org.apache.logging.log4j:log4j-bom` from 2.24.0 to 2.24.1 - [Release notes](https://github.com/apache/logging-log4j2/releases) - [Changelog](https://github.com/apache/logging-log4j2/blob/2.x/RELEASE-NOTES.adoc) - [Commits](https://github.com/apache/logging-log4j2/compare/rel/2.24.0...rel/2.24.1) Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.24.0 to 2.24.1 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3ced3a412f..efe1ea113a 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ ext { junit4Version = '4.13.2' junitJupiterVersion = '5.11.1' kotlinCoroutinesVersion = '1.8.1' - log4jVersion = '2.24.0' + log4jVersion = '2.24.1' logbackVersion = '1.5.8' lz4Version = '1.8.0' micrometerDocsVersion = '1.0.4' From 57689702c71b0f88d0e05958d37db61184bd96ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:14:16 +0000 Subject: [PATCH 041/111] Bump org.testcontainers:testcontainers-bom from 1.20.1 to 1.20.2 (#2848) Bumps [org.testcontainers:testcontainers-bom](https://github.com/testcontainers/testcontainers-java) from 1.20.1 to 1.20.2. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.20.1...1.20.2) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index efe1ea113a..2a68d442cc 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ ext { springDataVersion = '2024.0.4' springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' - testcontainersVersion = '1.20.1' + testcontainersVersion = '1.20.2' zstdJniVersion = '1.5.6-6' javaProjects = subprojects - project(':spring-amqp-bom') From 1b6ed72b0af1f15c3cab853a0dfa6e8735004d9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:14:30 +0000 Subject: [PATCH 042/111] Bump org.junit:junit-bom from 5.11.1 to 5.11.2 (#2850) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.1 to 5.11.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.1...r5.11.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2a68d442cc..6f983cea93 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ ext { jacksonBomVersion = '2.18.0' jaywayJsonPathVersion = '2.9.0' junit4Version = '4.13.2' - junitJupiterVersion = '5.11.1' + junitJupiterVersion = '5.11.2' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' logbackVersion = '1.5.8' From 310a76d919d4aa8749ec6c1d1657f5eb8c243186 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 7 Oct 2024 17:08:29 -0400 Subject: [PATCH 043/111] GH-2688: Introduce a `MessageProperties.RETRY_COUNT` header Fixes: https://github.com/spring-projects/spring-amqp/issues/2688 Since RabbitMQ 4.0 ignored `x-*` headers sent from the client, there is no way to rely on the `x-death.count` increment be done on the broker side when manual re-publishing approach is done from the application side. * Add a `retry-count` header for manual retries. * Map the `x-death.count` into this header on the client for convenience * Document how this `retry-count` header can be used --- .../amqp/core/MessageProperties.java | 36 ++++++++++++++++++ .../amqp/support/AmqpHeaders.java | 8 +++- .../amqp/support/SimpleAmqpHeaderMapper.java | 7 ++-- .../DefaultMessagePropertiesConverter.java | 21 ++++++++++- ...ering-from-errors-and-broker-failures.adoc | 37 +++++++++++++++++++ .../antora/modules/ROOT/pages/whats-new.adoc | 7 +++- 6 files changed, 110 insertions(+), 6 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java b/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java index efb2af4b61..75a402a4d2 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java @@ -63,6 +63,13 @@ public class MessageProperties implements Serializable { public static final String X_DELAY = "x-delay"; + /** + * The custom header to represent a number of retries a message is republished. + * In case of server-side DLX, this header contains the value of {@code x-death.count} property. + * When republish is done manually, this header has to be incremented by the application. + */ + public static final String RETRY_COUNT = "retry-count"; + public static final String DEFAULT_CONTENT_TYPE = CONTENT_TYPE_BYTES; public static final MessageDeliveryMode DEFAULT_DELIVERY_MODE = MessageDeliveryMode.PERSISTENT; @@ -131,6 +138,8 @@ public class MessageProperties implements Serializable { private MessageDeliveryMode receivedDeliveryMode; + private long retryCount; + private boolean finalRetryForMessageWithNoId; private long publishSequenceNumber; @@ -468,6 +477,33 @@ public void setDelayLong(Long delay) { this.headers.put(X_DELAY, delay); } + /** + * The number of retries for this message over broker. + * @return the retry count + * @since 3.2 + */ + public long getRetryCount() { + return this.retryCount; + } + + /** + * Set a number of retries for this message over broker. + * @param retryCount the retry count. + * @since 3.2 + * @see #incrementRetryCount() + */ + public void setRetryCount(long retryCount) { + this.retryCount = retryCount; + } + + /** + * Increment a retry count for this message when it is re-published back to the broker. + * @since 3.2 + */ + public void incrementRetryCount() { + this.retryCount++; + } + public boolean isFinalRetryForMessageWithNoId() { return this.finalRetryForMessageWithNoId; } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/AmqpHeaders.java b/spring-amqp/src/main/java/org/springframework/amqp/support/AmqpHeaders.java index a4f64b6475..5478b48573 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/AmqpHeaders.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/AmqpHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -138,4 +138,10 @@ public abstract class AmqpHeaders { */ public static final String BATCH_SIZE = PREFIX + "batchSize"; + /** + * The number of retries for the message over server republishing. + * @since 3.2 + */ + public static final String RETRY_COUNT = PREFIX + "retryCount"; + } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java b/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java index 2885f91f46..3f3f5bffbb 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/SimpleAmqpHeaderMapper.java @@ -97,6 +97,8 @@ public void fromHeaders(MessageHeaders headers, MessageProperties amqpMessagePro amqpMessageProperties::setTimestamp) .acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.TYPE, String.class), amqpMessageProperties::setType) + .acceptIfNotNull(getHeaderIfAvailable(headers, AmqpHeaders.RETRY_COUNT, Long.class), + amqpMessageProperties::setRetryCount) .acceptIfHasText(getHeaderIfAvailable(headers, AmqpHeaders.USER_ID, String.class), amqpMessageProperties::setUserId); @@ -166,11 +168,10 @@ public MessageHeaders toHeaders(MessageProperties amqpMessageProperties) { .acceptIfHasText(AmqpHeaders.CONSUMER_TAG, amqpMessageProperties.getConsumerTag(), putString) .acceptIfHasText(AmqpHeaders.CONSUMER_QUEUE, amqpMessageProperties.getConsumerQueue(), putString); headers.put(AmqpHeaders.LAST_IN_BATCH, amqpMessageProperties.isLastInBatch()); + headers.put(AmqpHeaders.RETRY_COUNT, amqpMessageProperties.getRetryCount()); // Map custom headers - for (Map.Entry entry : amqpMessageProperties.getHeaders().entrySet()) { - headers.put(entry.getKey(), entry.getValue()); - } + headers.putAll(amqpMessageProperties.getHeaders()); } catch (Exception e) { if (logger.isWarnEnabled()) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java index 489107b7aa..24632abe0c 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java @@ -100,6 +100,12 @@ public MessageProperties toMessageProperties(BasicProperties source, @Nullable E target.setHeader(key, receivedDelayLongValue); } } + else if (MessageProperties.RETRY_COUNT.equals(key)) { + Object value = entry.getValue(); + if (value instanceof Number numberValue) { + target.setRetryCount(numberValue.longValue()); + } + } else { target.setHeader(key, convertLongStringIfNecessary(entry.getValue(), charset)); } @@ -134,13 +140,26 @@ public MessageProperties toMessageProperties(BasicProperties source, @Nullable E target.setRedelivered(envelope.isRedeliver()); target.setDeliveryTag(envelope.getDeliveryTag()); } + + if (target.getRetryCount() == 0) { + List> xDeathHeader = target.getXDeathHeader(); + if (!CollectionUtils.isEmpty(xDeathHeader)) { + target.setRetryCount((long) xDeathHeader.get(0).get("count")); + } + } + return target; } @Override public BasicProperties fromMessageProperties(final MessageProperties source, final String charset) { BasicProperties.Builder target = new BasicProperties.Builder(); - target.headers(this.convertHeadersIfNecessary(source.getHeaders())) + Map headers = convertHeadersIfNecessary(source.getHeaders()); + long retryCount = source.getRetryCount(); + if (retryCount > 0) { + headers.put(MessageProperties.RETRY_COUNT, retryCount); + } + target.headers(headers) .timestamp(source.getTimestamp()) .messageId(source.getMessageId()) .userId(source.getUserId()) diff --git a/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc b/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc index f9c89b3e77..fb35a9723f 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/resilience-recovering-from-errors-and-broker-failures.adoc @@ -210,3 +210,40 @@ When `true`, it travers exception causes until it finds a match or there is no c To use this classifier for retry, you can use a `SimpleRetryPolicy` created with the constructor that takes the max attempts, the `Map` of `Exception` instances, and the boolean (`traverseCauses`) and inject this policy into the `RetryTemplate`. +[[retry-over-broker]] +== Retry Over Broker + +The message dead-lettered from the queue can be republished back to this queue after re-routing from a DLX. +This retry behaviour is controlled on the broker side via an `x-death` header. +More information about this approach in the official https://www.rabbitmq.com/docs/dlx[RabbitMQ documentation]. + +The other approach is to re-publish failed message back to the original exchange manually from the application. +Starting with version `4.0`, the RabbitMQ broker does not consider `x-death` header sent from the client. +Essentially, any `x-*` headers are ignored from the client. + +To mitigate this new behavior of the RabbitMQ broker, Spring AMQP has introduced a `retry_count` header starting with version 3.2. +When this header is absent and a server side DLX is in action, the `x-death.count` property is mapped to this header. +When the failed message is re-published manually for retries, the `retry_count` header value has to be incremented manually. +See `MessageProperties.incrementRetryCount()` JavaDocs for more information. + +The following example summarise an algorithm for manual retry over the broker: + +[source,java] +---- +@RabbitListener(queueNames = "some_queue") +public void rePublish(Message message) { + try { + // Process message + } + catch (Exception ex) { + Long retryCount = message.getMessageProperties().getRetryCount(); + if (retryCount < 3) { + message.getMessageProperties().incrementRetryCount(); + this.rabbitTemplate.send("", "some_queue", message); + } + else { + throw new ImmediateAcknowledgeAmqpException("Failed after 4 attempts"); + } + } +} +---- diff --git a/src/reference/antora/modules/ROOT/pages/whats-new.adoc b/src/reference/antora/modules/ROOT/pages/whats-new.adoc index 3258c28f44..0e643ec6ca 100644 --- a/src/reference/antora/modules/ROOT/pages/whats-new.adoc +++ b/src/reference/antora/modules/ROOT/pages/whats-new.adoc @@ -13,4 +13,9 @@ This version requires Spring Framework 6.2. [[x32-consistent-hash-exchange]] === Consistent Hash Exchange -The convenient `ConsistentHashExchange` and respective `ExchangeBuilder.consistentHashExchange()` API has been introduced. \ No newline at end of file +The convenient `ConsistentHashExchange` and respective `ExchangeBuilder.consistentHashExchange()` API has been introduced. + +[[x32-retry-count-header]] +=== The `retry_count` header + +The `retry_count` header should be used now instead of relying on server side increment for the `x-death.count` property. \ No newline at end of file From 7f714b0d3554858657f728042973bb268406a5fc Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 7 Oct 2024 17:23:08 -0400 Subject: [PATCH 044/111] Remove `getPrefix()` from `ObservationDocumentation` impls --- .../support/micrometer/RabbitListenerObservation.java | 7 ++----- .../support/micrometer/RabbitTemplateObservation.java | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java index f5f8528491..a9bb6dabd8 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java @@ -27,6 +27,8 @@ * * @author Gary Russell * @author Vincent Meunier + * @author Artem Bilan + * * @since 3.0 */ public enum RabbitListenerObservation implements ObservationDocumentation { @@ -41,11 +43,6 @@ public Class> getDefaultConve return DefaultRabbitListenerObservationConvention.class; } - @Override - public String getPrefix() { - return "spring.rabbit.listener"; - } - @Override public KeyName[] getLowCardinalityKeyNames() { return ListenerLowCardinalityTags.values(); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java index 6008e1e06d..06a5551878 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitTemplateObservation.java @@ -27,6 +27,8 @@ * * @author Gary Russell * @author Vincent Meunier + * @author Artem Bilan + * * @since 3.0 * */ @@ -42,11 +44,6 @@ public Class> getDefaultConve return DefaultRabbitTemplateObservationConvention.class; } - @Override - public String getPrefix() { - return "spring.rabbit.template"; - } - @Override public KeyName[] getLowCardinalityKeyNames() { return TemplateLowCardinalityTags.values(); From 1c429b81d965b533b88413fb23e9ddbe988c0d36 Mon Sep 17 00:00:00 2001 From: smallbun <30397655+leshalv@users.noreply.github.com> Date: Wed, 9 Oct 2024 03:56:01 +0800 Subject: [PATCH 045/111] Add `RabbitTemplate.getBeforePublishPostProcessors()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `RabbitTemplate` class currently provides a `addBeforePublishPostProcessors` method to configure `MessagePostProcessor` instances that can modify messages before they are sent. However, there is no corresponding `getBeforePublishPostProcessors` method to retrieve the currently configured processors. This PR introduces the `getBeforePublishPostProcessors` method, enhancing the flexibility and configurability of `RabbitTemplate`. #### Justification: 1. **Increased Flexibility**: - While `addBeforePublishPostProcessors` allows users to configure message processors, there is currently no way to retrieve or modify the existing `MessagePostProcessor` list. Adding `getBeforePublishPostProcessors` gives users the ability to access and modify these processors dynamically, allowing for greater flexibility in scenarios where message processing needs to be altered based on context. 2. **Support for Multiple `RabbitTemplate` Instances**: - In more complex applications, it's common to create multiple `RabbitTemplate` instances to handle different business logic. For instance, the `ConfirmCallback` mechanism is globally applied, but by manually creating different `RabbitTemplate` instances, users can configure distinct callbacks for each instance. Introducing the `getBeforePublishPostProcessors` method will allow users to retrieve and reuse message processors between different `RabbitTemplate` instances, enhancing flexibility when handling different message routing and confirmation scenarios. 3. **Improved Consistency**: - Spring generally follows a "getter-setter" pattern for its components, and many classes offer both methods for configuring and retrieving values. By providing `getBeforePublishPostProcessors`, the API will become more consistent, following Spring’s design principles and making it easier for developers to interact with the `RabbitTemplate` class. 4. **Better Support for Advanced Use Cases**: - In advanced scenarios where users need to dynamically add or remove message processors based on business needs, the ability to retrieve the current processors simplifies the code. Without this getter method, developers need to manually track and manage `MessagePostProcessor` lists, which adds unnecessary complexity and can lead to duplication of logic. 5. **Enhanced Developer Experience**: - Having the ability to get the current `MessagePostProcessor` list helps developers debug and analyze the message pipeline more easily. This makes it simpler to understand how messages are being transformed before being sent, improving both the developer experience and troubleshooting process. --- .../amqp/rabbit/core/RabbitTemplate.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java index 5d2894c96c..3de6bbe7fb 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java @@ -633,6 +633,18 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.evaluationContext.addPropertyAccessor(new MapAccessor()); } + /** + * Return configured before post {@link MessagePostProcessor}s or {@code null}. + * @return configured before post {@link MessagePostProcessor}s or {@code null}. + * @since 3.2 + */ + @Nullable + public Collection getBeforePublishPostProcessors() { + return this.beforePublishPostProcessors != null + ? Collections.unmodifiableCollection(this.beforePublishPostProcessors) + : null; + } + /** * Set {@link MessagePostProcessor}s that will be invoked immediately before invoking * {@code Channel#basicPublish()}, after all other processing, except creating the From 8848f3bc16666021d7f87db3139804e33382ad5d Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 9 Oct 2024 03:00:29 +0700 Subject: [PATCH 046/111] `DefaultMessagePropertiesConverter`: improve conditions We can reduce `else if` condition in method `DefaultMessagePropertiesConverter.convertLongStringIfNecessary()` --- .../DefaultMessagePropertiesConverter.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java index 24632abe0c..44ccbdfe0e 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java @@ -42,6 +42,7 @@ * @author Soeren Unruh * @author Raylax Grey * @author Artem Bilan + * @author Ngoc Nhan * * @since 1.0 */ @@ -275,27 +276,24 @@ private Object convertLongString(LongString longString, String charset) { * @return the converted string. */ private Object convertLongStringIfNecessary(Object valueArg, String charset) { - Object value = valueArg; - if (value instanceof LongString longStr) { - value = convertLongString(longStr, charset); + if (valueArg instanceof LongString longStr) { + return convertLongString(longStr, charset); } - else if (value instanceof List) { - List convertedList = new ArrayList<>(((List) value).size()); - for (Object listValue : (List) value) { - convertedList.add(this.convertLongStringIfNecessary(listValue, charset)); - } - value = convertedList; + + if (valueArg instanceof List values) { + List convertedList = new ArrayList<>(values.size()); + values.forEach(value -> convertedList.add(this.convertLongStringIfNecessary(value, charset))); + return convertedList; } - else if (value instanceof Map) { - @SuppressWarnings("unchecked") - Map originalMap = (Map) value; + + if (valueArg instanceof Map originalMap) { Map convertedMap = new HashMap<>(); - for (Map.Entry entry : originalMap.entrySet()) { - convertedMap.put(entry.getKey(), this.convertLongStringIfNecessary(entry.getValue(), charset)); - } - value = convertedMap; + originalMap.forEach( + (key, value) -> convertedMap.put((String) key, this.convertLongStringIfNecessary(value, charset))); + return convertedMap; } - return value; + + return valueArg; } } From f5f368daae0f22c99e2e86910a7787280c3b2108 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Thu, 10 Oct 2024 21:13:10 +0700 Subject: [PATCH 047/111] Simplify the expression in some `equals()` methods --- .../java/org/springframework/amqp/core/Message.java | 12 ++++-------- .../springframework/amqp/core/MessageProperties.java | 10 +++------- .../springframework/amqp/core/QueueInformation.java | 12 ++++-------- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/Message.java b/spring-amqp/src/main/java/org/springframework/amqp/core/Message.java index 3cb4872102..4039013615 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/Message.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ * @author Gary Russell * @author Alex Panchenko * @author Artem Bilan + * @author Ngoc Nhan */ public class Message implements Serializable { @@ -168,14 +169,9 @@ public boolean equals(Object obj) { return false; } if (this.messageProperties == null) { - if (other.messageProperties != null) { - return false; - } - } - else if (!this.messageProperties.equals(other.messageProperties)) { - return false; + return other.messageProperties == null; } - return true; + return this.messageProperties.equals(other.messageProperties); } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java b/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java index 75a402a4d2..81e4954d4c 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/MessageProperties.java @@ -36,6 +36,7 @@ * @author Artem Bilan * @author Csaba Soti * @author Raylax Grey + * @author Ngoc Nhan */ public class MessageProperties implements Serializable { @@ -812,14 +813,9 @@ else if (!this.type.equals(other.type)) { return false; } if (this.userId == null) { - if (other.userId != null) { - return false; - } - } - else if (!this.userId.equals(other.userId)) { - return false; + return other.userId == null; } - return true; + return this.userId.equals(other.userId); } @Override // NOSONAR complexity diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/QueueInformation.java b/spring-amqp/src/main/java/org/springframework/amqp/core/QueueInformation.java index de914f9439..f2d8df2453 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/QueueInformation.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/QueueInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2019-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ * Information about a queue, resulting from a passive declaration. * * @author Gary Russell + * @author Ngoc Nhan * @since 2.2 * */ @@ -70,14 +71,9 @@ public boolean equals(Object obj) { } QueueInformation other = (QueueInformation) obj; if (this.name == null) { - if (other.name != null) { - return false; - } + return other.name == null; } - else if (!this.name.equals(other.name)) { - return false; - } - return true; + return this.name.equals(other.name); } @Override From 15a53a465907df608ae910f86a85632e7c7f4a52 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 10 Oct 2024 14:20:23 -0400 Subject: [PATCH 048/111] Upgrade deps including Gradle plugins * Remove some deps which are now managed transitively from RabbitMQ `stream-client` --- build.gradle | 27 ++++++++----------- .../amqp/rabbit/core/RabbitTemplate.java | 2 +- .../PublisherCallbackChannelTests.java | 4 +-- .../core/BatchingRabbitTemplateTests.java | 2 +- .../core/RabbitTemplateIntegrationTests.java | 2 +- .../amqp/rabbit/core/RabbitTemplateTests.java | 2 +- .../rabbit/listener/ErrorHandlerTests.java | 4 +-- .../SimpleMessageListenerContainerTests.java | 2 +- .../MessagingMessageListenerAdapterTests.java | 2 +- 9 files changed, 21 insertions(+), 26 deletions(-) diff --git a/build.gradle b/build.gradle index 6f983cea93..eb986c8bc4 100644 --- a/build.gradle +++ b/build.gradle @@ -18,13 +18,13 @@ buildscript { plugins { id 'base' id 'idea' - id 'org.ajoberstar.grgit' version '5.2.2' + id 'org.ajoberstar.grgit' version '5.3.0' id 'io.spring.nohttp' version '0.0.11' id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' id 'com.github.spotbugs' version '6.0.24' - id 'io.freefair.aggregate-javadoc' version '8.6' + id 'io.freefair.aggregate-javadoc' version '8.10.2' } description = 'Spring AMQP' @@ -49,9 +49,9 @@ ext { assertkVersion = '0.28.1' awaitilityVersion = '4.2.2' commonsCompressVersion = '1.27.1' - commonsHttpClientVersion = '5.3.1' + commonsHttpClientVersion = '5.4' commonsPoolVersion = '2.12.0' - hamcrestVersion = '2.2' + hamcrestVersion = '3.0' hibernateValidationVersion = '8.0.1.Final' jacksonBomVersion = '2.18.0' jaywayJsonPathVersion = '2.9.0' @@ -60,20 +60,17 @@ ext { kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' logbackVersion = '1.5.8' - lz4Version = '1.8.0' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-SNAPSHOT' - mockitoVersion = '5.13.0' - rabbitmqStreamVersion = '0.15.0' - rabbitmqVersion = '5.21.0' + mockitoVersion = '5.14.1' + rabbitmqStreamVersion = '0.17.0' + rabbitmqVersion = '5.22.0' reactorVersion = '2024.0.0-SNAPSHOT' - snappyVersion = '1.1.10.7' - springDataVersion = '2024.0.4' + springDataVersion = '2024.1.0-SNAPSHOT' springRetryVersion = '2.0.9' springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.20.2' - zstdJniVersion = '1.5.6-6' javaProjects = subprojects - project(':spring-amqp-bom') } @@ -315,7 +312,7 @@ configure(javaProjects) { subproject -> checkstyle { configDirectory.set(rootProject.file("src/checkstyle")) - toolVersion = '10.8.0' + toolVersion = '10.18.2' } jar { @@ -470,12 +467,10 @@ project('spring-rabbit-stream') { testRuntimeOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml' testRuntimeOnly 'com.fasterxml.jackson.module:jackson-module-kotlin' testRuntimeOnly "org.apache.commons:commons-compress:$commonsCompressVersion" - testRuntimeOnly "org.xerial.snappy:snappy-java:$snappyVersion" - testRuntimeOnly "org.lz4:lz4-java:$lz4Version" - testRuntimeOnly "com.github.luben:zstd-jni:$zstdJniVersion" + testImplementation "org.testcontainers:rabbitmq" testImplementation "org.testcontainers:junit-jupiter" - testImplementation "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion" + testImplementation 'org.apache.logging.log4j:log4j-slf4j-impl' testImplementation 'org.springframework:spring-webflux' testImplementation 'io.micrometer:micrometer-observation-test' testImplementation 'io.micrometer:micrometer-tracing-bridge-brave' diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java index 3de6bbe7fb..77315c4020 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitTemplate.java @@ -2833,7 +2833,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie return consumer; } - private static class PendingReply { + private static final class PendingReply { @Nullable private volatile String savedReplyTo; diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelTests.java index 6dcd35b9c6..6872f3f96e 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2019-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -183,7 +183,7 @@ void confirmAlwaysAfterReturn() throws InterruptedException { assertThat(listener.calls).containsExactly("return", "confirm", "return", "confirm"); } - private static class TheListener implements Listener { + private static final class TheListener implements Listener { private final UUID uuid = UUID.randomUUID(); diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplateTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplateTests.java index e5587a979f..b554fdd14c 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplateTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/BatchingRabbitTemplateTests.java @@ -676,7 +676,7 @@ private int getStreamLevel(Object stream) throws Exception { return TestUtils.getPropertyValue(zipStream, "def.level", Integer.class); } - private static class HeaderPostProcessor implements MessagePostProcessor { + private static final class HeaderPostProcessor implements MessagePostProcessor { @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().getHeaders().put("someHeader", "someValue"); diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateIntegrationTests.java index 00dea012c1..06109d6606 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateIntegrationTests.java @@ -1733,7 +1733,7 @@ private class PlannedException extends RuntimeException { } @SuppressWarnings("serial") - private class TestTransactionManager extends AbstractPlatformTransactionManager { + private final class TestTransactionManager extends AbstractPlatformTransactionManager { @Override protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateTests.java index cc8683616e..5e6fb2a6d3 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplateTests.java @@ -742,7 +742,7 @@ protected void doRollback(DefaultTransactionStatus status) throws TransactionExc } - private class DoNothingMPP implements MessagePostProcessor { + private static final class DoNothingMPP implements MessagePostProcessor { @Override public Message postProcessMessage(Message message) throws AmqpException { diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/ErrorHandlerTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/ErrorHandlerTests.java index 2d9bcf0947..6ae1f35f18 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/ErrorHandlerTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/ErrorHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2016-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -127,7 +127,7 @@ private void doTest(Throwable cause) { new MessageProperties()))); } - private static class Foo { + private static final class Foo { @SuppressWarnings("unused") public void foo(String foo) { diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainerTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainerTests.java index f668ba0276..ed4580e603 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainerTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainerTests.java @@ -882,7 +882,7 @@ private void waitForConsumersToStop(Set consumers) { } @SuppressWarnings("serial") - private static class TestTransactionManager extends AbstractPlatformTransactionManager { + private static final class TestTransactionManager extends AbstractPlatformTransactionManager { @Override protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapterTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapterTests.java index 157e999a0f..f59ae1ce60 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapterTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapterTests.java @@ -488,7 +488,7 @@ public void withHeaders(Foo foo, @Headers Map headers) { } - private static class Foo { + private static final class Foo { private String foo; From 2d3f4b4e993b6ad2f37301f24b43a7dc485156a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:04:57 +0000 Subject: [PATCH 049/111] Bump ch.qos.logback:logback-classic from 1.5.8 to 1.5.9 (#2856) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.8 to 1.5.9. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.8...v_1.5.9) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index eb986c8bc4..a1de461d86 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ ext { junitJupiterVersion = '5.11.2' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' - logbackVersion = '1.5.8' + logbackVersion = '1.5.9' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-SNAPSHOT' From 09b147900dc2cfb837c9b1eb5b5e17882185258d Mon Sep 17 00:00:00 2001 From: Volodymyr Date: Mon, 14 Oct 2024 16:18:42 +0300 Subject: [PATCH 050/111] Fix typo in sending-messages.adoc --- .../antora/modules/ROOT/pages/amqp/sending-messages.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc b/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc index 0d1eaa72da..6ff5f1257d 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/sending-messages.adoc @@ -13,7 +13,7 @@ void send(String exchange, String routingKey, Message message) throws AmqpExcept ---- We can begin our discussion with the last method in the preceding listing, since it is actually the most explicit. -It lets an AMQP exchange name (along with a routing key)be provided at runtime. +It lets an AMQP exchange name (along with a routing key) be provided at runtime. The last parameter is the callback that is responsible for actual creating the message instance. An example of using this method to send a message might look like this: The following example shows how to use the `send` method to send a message: From ef23aa9f7f9485ebc50e45a0eb9ed57083c9ca49 Mon Sep 17 00:00:00 2001 From: DongMin <62013201+eyeben@users.noreply.github.com> Date: Tue, 15 Oct 2024 22:37:04 +0900 Subject: [PATCH 051/111] Rename `ConnnectionListenerTests` class without typos --- ...nnectionListenerTests.java => ConnectionListenerTests.java} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/{ConnnectionListenerTests.java => ConnectionListenerTests.java} (97%) diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnnectionListenerTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnectionListenerTests.java similarity index 97% rename from spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnnectionListenerTests.java rename to spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnectionListenerTests.java index 03638c6a15..606c71cf4c 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnnectionListenerTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/ConnectionListenerTests.java @@ -27,10 +27,11 @@ /** * @author Gary Russell + * @author DongMin Park * @since 2.2.17 * */ -public class ConnnectionListenerTests { +public class ConnectionListenerTests { @Test void cantConnectCCF() { From 347c96ad2a447a44824eb72a178629287ecea5f2 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 15 Oct 2024 16:42:38 -0400 Subject: [PATCH 052/111] Improve some code in the `AbstractDeclarable` * Add `Declarable.setAdminsThatShouldDeclare(@Nullable)` * Improve `RabbitAdminDeclarationTests` * Fix typo in the `AbstractMessageListenerContainer` JavaDoc --- .../amqp/core/AbstractDeclarable.java | 15 ++-- .../springframework/amqp/core/Declarable.java | 4 +- .../AbstractMessageListenerContainer.java | 2 +- .../core/RabbitAdminDeclarationTests.java | 88 +++++++++---------- 4 files changed, 51 insertions(+), 58 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java index 678620e914..2a18103b5e 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java @@ -25,7 +25,6 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; - import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -40,15 +39,15 @@ */ public abstract class AbstractDeclarable implements Declarable { - private final Lock lock = new ReentrantLock(); + private final Lock lock = new ReentrantLock(); - private boolean shouldDeclare = true; + private final Map arguments; - private Collection declaringAdmins = new ArrayList<>(); + private boolean shouldDeclare = true; private boolean ignoreDeclarationExceptions; - private final Map arguments; + private Collection declaringAdmins = new ArrayList<>(); public AbstractDeclarable() { this(null); @@ -74,7 +73,7 @@ public boolean shouldDeclare() { } /** - * Whether or not this object should be automatically declared + * Whether this object should be automatically declared * by any {@code AmqpAdmin}. Default is {@code true}. * @param shouldDeclare true or false. */ @@ -102,14 +101,14 @@ public void setIgnoreDeclarationExceptions(boolean ignoreDeclarationExceptions) } @Override - public void setAdminsThatShouldDeclare(Object... adminArgs) { + public void setAdminsThatShouldDeclare(@Nullable Object... adminArgs) { Collection admins = new ArrayList<>(); if (adminArgs != null) { if (adminArgs.length > 1) { Assert.noNullElements(adminArgs, "'admins' cannot contain null elements"); } if (adminArgs.length > 0 && !(adminArgs.length == 1 && adminArgs[0] == null)) { - admins.addAll(Arrays.asList(adminArgs)); + admins = Arrays.asList(adminArgs); } } this.declaringAdmins = admins; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/Declarable.java b/spring-amqp/src/main/java/org/springframework/amqp/core/Declarable.java index da6d4788d9..b6948116fc 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/Declarable.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/Declarable.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ public interface Declarable { * the behavior such that all admins will declare the object. * @param adminArgs The admins. */ - void setAdminsThatShouldDeclare(Object... adminArgs); + void setAdminsThatShouldDeclare(@Nullable Object... adminArgs); /** * Add an argument to the declarable. diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractMessageListenerContainer.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractMessageListenerContainer.java index 7c3b44618f..80df1dab3d 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractMessageListenerContainer.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractMessageListenerContainer.java @@ -1490,7 +1490,7 @@ protected void invokeErrorHandler(Throwable ex) { // ------------------------------------------------------------------------- /** - * Execute the specified listener, committing or rolling back the transaction afterwards (if necessary). + * Execute the specified listener, committing or rolling back the transaction afterward (if necessary). * @param channel the Rabbit Channel to operate on * @param data the received Rabbit Message * @see #invokeListener diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java index 3d82f4c14d..fe9b092554 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package org.springframework.amqp.rabbit.core; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyMap; @@ -79,8 +79,8 @@ public void testUnconditional() throws Exception { given(cf.createConnection()).willReturn(conn); given(conn.createChannel(false)).willReturn(channel); given(channel.queueDeclare("foo", true, false, false, new HashMap<>())) - .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); - final AtomicReference listener = new AtomicReference(); + .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); + AtomicReference listener = new AtomicReference<>(); willAnswer(invocation -> { listener.set((ConnectionListener) invocation.getArguments()[0]); return null; @@ -100,7 +100,7 @@ public void testUnconditional() throws Exception { listener.get().onCreate(conn); verify(channel).queueDeclare("foo", true, false, false, new HashMap<>()); - verify(channel).exchangeDeclare("bar", "direct", true, false, false, new HashMap()); + verify(channel).exchangeDeclare("bar", "direct", true, false, false, new HashMap<>()); verify(channel).queueBind("foo", "bar", "foo", new HashMap<>()); } @@ -108,7 +108,7 @@ public void testUnconditional() throws Exception { public void testNoDeclareWithCachedConnections() throws Exception { com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class); - final List mockChannels = new ArrayList(); + List mockChannels = new ArrayList<>(); AtomicInteger connectionNumber = new AtomicInteger(); willAnswer(invocation -> { @@ -153,8 +153,8 @@ public void testUnconditionalWithExplicitFactory() throws Exception { given(cf.createConnection()).willReturn(conn); given(conn.createChannel(false)).willReturn(channel); given(channel.queueDeclare("foo", true, false, false, new HashMap<>())) - .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); - final AtomicReference listener = new AtomicReference(); + .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); + AtomicReference listener = new AtomicReference<>(); willAnswer(invocation -> { listener.set(invocation.getArgument(0)); return null; @@ -177,7 +177,7 @@ public void testUnconditionalWithExplicitFactory() throws Exception { listener.get().onCreate(conn); verify(channel).queueDeclare("foo", true, false, false, new HashMap<>()); - verify(channel).exchangeDeclare("bar", "direct", true, false, false, new HashMap()); + verify(channel).exchangeDeclare("bar", "direct", true, false, false, new HashMap<>()); verify(channel).queueBind("foo", "bar", "foo", new HashMap<>()); } @@ -189,8 +189,9 @@ public void testSkipBecauseDifferentFactory() throws Exception { Channel channel = mock(Channel.class); given(cf.createConnection()).willReturn(conn); given(conn.createChannel(false)).willReturn(channel); - given(channel.queueDeclare("foo", true, false, false, null)).willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); - final AtomicReference listener = new AtomicReference(); + given(channel.queueDeclare("foo", true, false, false, null)) + .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); + AtomicReference listener = new AtomicReference<>(); willAnswer(invocation -> { listener.set(invocation.getArgument(0)); return null; @@ -215,20 +216,21 @@ public void testSkipBecauseDifferentFactory() throws Exception { verify(channel, never()).queueDeclare(eq("foo"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); verify(channel, never()) - .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); + .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); verify(channel, never()).queueBind(eq("foo"), eq("bar"), eq("foo"), any(Map.class)); } @SuppressWarnings("unchecked") @Test - public void testSkipBecauseShouldntDeclare() throws Exception { + public void testSkipBecauseShouldNotDeclare() throws Exception { ConnectionFactory cf = mock(ConnectionFactory.class); Connection conn = mock(Connection.class); Channel channel = mock(Channel.class); given(cf.createConnection()).willReturn(conn); given(conn.createChannel(false)).willReturn(channel); - given(channel.queueDeclare("foo", true, false, false, null)).willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); - final AtomicReference listener = new AtomicReference(); + given(channel.queueDeclare("foo", true, false, false, null)) + .willReturn(new AMQImpl.Queue.DeclareOk("foo", 0, 0)); + AtomicReference listener = new AtomicReference<>(); willAnswer(invocation -> { listener.set(invocation.getArgument(0)); return null; @@ -252,7 +254,7 @@ public void testSkipBecauseShouldntDeclare() throws Exception { verify(channel, never()).queueDeclare(eq("foo"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); verify(channel, never()) - .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); + .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), anyBoolean(), any(Map.class)); verify(channel, never()).queueBind(eq("foo"), eq("bar"), eq("foo"), any(Map.class)); } @@ -263,9 +265,8 @@ public void testJavaConfig() throws Exception { verify(Config.channel1).queueDeclare("foo", true, false, false, new HashMap<>()); verify(Config.channel1, never()).queueDeclare("baz", true, false, false, new HashMap<>()); verify(Config.channel1).queueDeclare("qux", true, false, false, new HashMap<>()); - verify(Config.channel1).exchangeDeclare("bar", "direct", true, false, true, new HashMap()); + verify(Config.channel1).exchangeDeclare("bar", "direct", true, false, true, new HashMap<>()); verify(Config.channel1).queueBind("foo", "bar", "foo", new HashMap<>()); - Config.listener2.onCreate(Config.conn2); verify(Config.channel2, never()) .queueDeclare(eq("foo"), anyBoolean(), anyBoolean(), anyBoolean(), isNull()); @@ -273,9 +274,8 @@ public void testJavaConfig() throws Exception { verify(Config.channel2).queueDeclare("qux", true, false, false, new HashMap<>()); verify(Config.channel2, never()) .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), - anyBoolean(), anyMap()); + anyBoolean(), anyMap()); verify(Config.channel2, never()).queueBind(eq("foo"), eq("bar"), eq("foo"), anyMap()); - Config.listener3.onCreate(Config.conn3); verify(Config.channel3, never()) .queueDeclare(eq("foo"), anyBoolean(), anyBoolean(), anyBoolean(), isNull()); @@ -286,7 +286,7 @@ public void testJavaConfig() throws Exception { verify(Config.channel3, never()).queueDeclare("qux", true, false, false, new HashMap<>()); verify(Config.channel3, never()) .exchangeDeclare(eq("bar"), eq("direct"), anyBoolean(), anyBoolean(), - anyBoolean(), anyMap()); + anyBoolean(), anyMap()); verify(Config.channel3, never()).queueBind(eq("foo"), eq("bar"), eq("foo"), anyMap()); context.close(); @@ -316,13 +316,9 @@ public void testAddRemove() { assertThat(queue.getDeclaringAdmins()).hasSize(2); queue.setAdminsThatShouldDeclare((Object[]) null); assertThat(queue.getDeclaringAdmins()).hasSize(0); - try { - queue.setAdminsThatShouldDeclare(null, admin1); - fail("Expected Exception"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains("'admins' cannot contain null elements"); - } + assertThatIllegalArgumentException() + .isThrownBy(() -> queue.setAdminsThatShouldDeclare(null, admin1)) + .withMessageContaining("'admins' cannot contain null elements"); } @Test @@ -348,17 +344,17 @@ public void testNoOpWhenNothingToDeclare() throws Exception { @Configuration public static class Config { - private static Connection conn1 = mock(Connection.class); + private static final Connection conn1 = mock(); - private static Connection conn2 = mock(Connection.class); + private static final Connection conn2 = mock(); - private static Connection conn3 = mock(Connection.class); + private static final Connection conn3 = mock(); - private static Channel channel1 = mock(Channel.class); + private static final Channel channel1 = mock(); - private static Channel channel2 = mock(Channel.class); + private static final Channel channel2 = mock(); - private static Channel channel3 = mock(Channel.class); + private static final Channel channel3 = mock(); private static ConnectionListener listener1; @@ -371,9 +367,9 @@ public ConnectionFactory cf1() throws IOException { ConnectionFactory connectionFactory = mock(ConnectionFactory.class); given(connectionFactory.createConnection()).willReturn(conn1); given(conn1.createChannel(false)).willReturn(channel1); - willAnswer(inv -> { - return new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0); - }).given(channel1).queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); + willAnswer(inv -> new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0)) + .given(channel1) + .queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); willAnswer(invocation -> { listener1 = invocation.getArgument(0); return null; @@ -386,9 +382,9 @@ public ConnectionFactory cf2() throws IOException { ConnectionFactory connectionFactory = mock(ConnectionFactory.class); given(connectionFactory.createConnection()).willReturn(conn2); given(conn2.createChannel(false)).willReturn(channel2); - willAnswer(inv -> { - return new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0); - }).given(channel2).queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); + willAnswer(inv -> new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0)) + .given(channel2) + .queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); willAnswer(invocation -> { listener2 = invocation.getArgument(0); return null; @@ -401,9 +397,9 @@ public ConnectionFactory cf3() throws IOException { ConnectionFactory connectionFactory = mock(ConnectionFactory.class); given(connectionFactory.createConnection()).willReturn(conn3); given(conn3.createChannel(false)).willReturn(channel3); - willAnswer(inv -> { - return new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0); - }).given(channel3).queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); + willAnswer(inv -> new AMQImpl.Queue.DeclareOk(inv.getArgument(0), 0, 0)) + .given(channel3) + .queueDeclare(anyString(), anyBoolean(), anyBoolean(), anyBoolean(), any()); willAnswer(invocation -> { listener3 = invocation.getArgument(0); return null; @@ -413,14 +409,12 @@ public ConnectionFactory cf3() throws IOException { @Bean public RabbitAdmin admin1() throws IOException { - RabbitAdmin rabbitAdmin = new RabbitAdmin(cf1()); - return rabbitAdmin; + return new RabbitAdmin(cf1()); } @Bean public RabbitAdmin admin2() throws IOException { - RabbitAdmin rabbitAdmin = new RabbitAdmin(cf2()); - return rabbitAdmin; + return new RabbitAdmin(cf2()); } @Bean From d87f2689439768ee7563a899a7b9a6f93d5d9859 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 16 Oct 2024 20:57:57 +0700 Subject: [PATCH 053/111] Improve conditions for more code readability * Reduce `else` condition * Improve condition for returning type and avoiding NPE * Polish diamond operator and pattern matching usage --- .../springframework/amqp/core/Address.java | 22 ++++----------- .../springframework/amqp/core/Binding.java | 5 ++-- .../amqp/core/BindingBuilder.java | 12 ++++---- .../converter/AbstractJavaTypeMapper.java | 8 ++---- ...ContentTypeDelegatingMessageConverter.java | 5 ++-- .../MarshallingMessageConverter.java | 10 +++---- .../converter/MessagingMessageConverter.java | 6 ++-- .../converter/RemoteInvocationResult.java | 12 ++++---- .../AbstractDecompressingPostProcessor.java | 6 ++-- .../DelegatingDecompressingPostProcessor.java | 28 +++++++++---------- .../amqp/utils/test/TestUtils.java | 12 ++++---- .../amqp/core/AddressTests.java | 6 +++- 12 files changed, 61 insertions(+), 71 deletions(-) diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/Address.java b/spring-amqp/src/main/java/org/springframework/amqp/core/Address.java index c1d10642fb..564c752d16 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/Address.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/Address.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.amqp.core; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -39,6 +40,7 @@ * @author Dave Syer * @author Artem Bilan * @author Gary Russell + * @author Ngoc Nhan */ public class Address { @@ -111,21 +113,9 @@ public String getRoutingKey() { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Address address = (Address) o; - - return !(this.exchangeName != null - ? !this.exchangeName.equals(address.exchangeName) - : address.exchangeName != null) - && !(this.routingKey != null - ? !this.routingKey.equals(address.routingKey) - : address.routingKey != null); + return o instanceof Address address + && Objects.equals(this.exchangeName, address.exchangeName) + && Objects.equals(this.routingKey, address.routingKey); } @Override diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/Binding.java b/spring-amqp/src/main/java/org/springframework/amqp/core/Binding.java index a5ee74273f..ac2ac58acd 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/Binding.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/Binding.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ * @author Mark Fisher * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * * @see AmqpAdmin */ @@ -74,7 +75,7 @@ public Binding(@Nullable Queue lazyQueue, @Nullable String destination, Destinat String exchange, @Nullable String routingKey, @Nullable Map arguments) { super(arguments); - Assert.isTrue(lazyQueue == null || destinationType.equals(DestinationType.QUEUE), + Assert.isTrue(lazyQueue == null || destinationType == DestinationType.QUEUE, "'lazyQueue' must be null for destination type " + destinationType); Assert.isTrue(lazyQueue != null || destination != null, "`destination` cannot be null"); this.lazyQueue = lazyQueue; diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java index 5eceadd960..d297f16d9d 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/BindingBuilder.java @@ -231,12 +231,12 @@ public static final class TopicExchangeRoutingKeyConfigurer extends AbstractRout public Binding with(String routingKey) { return new Binding(destination.queue, destination.name, destination.type, exchange, routingKey, - Collections.emptyMap()); + Collections.emptyMap()); } public Binding with(Enum routingKeyEnum) { return new Binding(destination.queue, destination.name, destination.type, exchange, - routingKeyEnum.toString(), Collections.emptyMap()); + routingKeyEnum.toString(), Collections.emptyMap()); } } @@ -282,7 +282,7 @@ public Binding and(Map map) { public Binding noargs() { return new Binding(this.configurer.destination.queue, this.configurer.destination.name, this.configurer.destination.type, this.configurer.exchange, - this.routingKey, Collections.emptyMap()); + this.routingKey, Collections.emptyMap()); } } @@ -298,17 +298,17 @@ public static final class DirectExchangeRoutingKeyConfigurer extends AbstractRou public Binding with(String routingKey) { return new Binding(destination.queue, destination.name, destination.type, exchange, routingKey, - Collections.emptyMap()); + Collections.emptyMap()); } public Binding with(Enum routingKeyEnum) { return new Binding(destination.queue, destination.name, destination.type, exchange, - routingKeyEnum.toString(), Collections.emptyMap()); + routingKeyEnum.toString(), Collections.emptyMap()); } public Binding withQueueName() { return new Binding(destination.queue, destination.name, destination.type, exchange, destination.name, - Collections.emptyMap()); + Collections.emptyMap()); } } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java index 76531523be..e19c62dc17 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/AbstractJavaTypeMapper.java @@ -99,11 +99,9 @@ protected String retrieveHeader(MessageProperties properties, String headerName) protected String retrieveHeaderAsString(MessageProperties properties, String headerName) { Map headers = properties.getHeaders(); Object classIdFieldNameValue = headers.get(headerName); - String classId = null; - if (classIdFieldNameValue != null) { - classId = classIdFieldNameValue.toString(); - } - return classId; + return classIdFieldNameValue != null + ? classIdFieldNameValue.toString() + : null; } private void createReverseMap() { diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java index 0fad672ee1..35fb9d901c 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/ContentTypeDelegatingMessageConverter.java @@ -109,9 +109,8 @@ protected MessageConverter getConverterForContentType(String contentType) { if (delegate == null) { throw new MessageConversionException("No delegate converter is specified for content type " + contentType); } - else { - return delegate; - } + + return delegate; } } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MarshallingMessageConverter.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MarshallingMessageConverter.java index 25f77c9cd7..6d94890221 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MarshallingMessageConverter.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MarshallingMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ * @author Arjen Poutsma * @author Juergen Hoeller * @author James Carr + * @author Ngoc Nhan * @see org.springframework.amqp.core.AmqpTemplate#convertAndSend(Object) * @see org.springframework.amqp.core.AmqpTemplate#receiveAndConvert() */ @@ -77,10 +78,9 @@ public MarshallingMessageConverter(Marshaller marshaller) { "interface. Please set an Unmarshaller explicitly by using the " + "MarshallingMessageConverter(Marshaller, Unmarshaller) constructor."); } - else { - this.marshaller = marshaller; - this.unmarshaller = (Unmarshaller) marshaller; - } + + this.marshaller = marshaller; + this.unmarshaller = (Unmarshaller) marshaller; } /** diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessagingMessageConverter.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessagingMessageConverter.java index 0c91aac106..5bc545086b 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessagingMessageConverter.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessagingMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2020 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ * is considered to be a request). * * @author Stephane Nicoll + * @author Ngoc Nhan * @since 1.4 */ public class MessagingMessageConverter implements MessageConverter, InitializingBean { @@ -104,11 +105,10 @@ public void afterPropertiesSet() { public org.springframework.amqp.core.Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { - if (!(object instanceof Message)) { + if (!(object instanceof Message input)) { throw new IllegalArgumentException("Could not convert [" + object + "] - only [" + Message.class.getName() + "] is handled by this converter"); } - Message input = (Message) object; this.headerMapper.fromHeaders(input.getHeaders(), messageProperties); org.springframework.amqp.core.Message amqpMessage = this.payloadConverter.toMessage( input.getPayload(), messageProperties); diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/RemoteInvocationResult.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/RemoteInvocationResult.java index 7d08e1d139..6945162895 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/RemoteInvocationResult.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/RemoteInvocationResult.java @@ -26,6 +26,7 @@ * * @author Juergen Hoeller * @author Gary Russell + * @author Ngoc Nhan * @since 3.0 */ public class RemoteInvocationResult implements Serializable { @@ -142,16 +143,13 @@ public boolean hasInvocationTargetException() { @Nullable public Object recreate() throws Throwable { if (this.exception != null) { - Throwable exToThrow = this.exception; - if (this.exception instanceof InvocationTargetException invocationTargetException) { - exToThrow = invocationTargetException.getTargetException(); - } + Throwable exToThrow = this.exception instanceof InvocationTargetException invocationTargetException + ? invocationTargetException.getTargetException() + : this.exception; RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow); throw exToThrow; } - else { - return this.value; - } + return this.value; } } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/AbstractDecompressingPostProcessor.java b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/AbstractDecompressingPostProcessor.java index 249f0e25e4..3c87829cff 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/AbstractDecompressingPostProcessor.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/AbstractDecompressingPostProcessor.java @@ -38,6 +38,7 @@ * the final content encoding of the decompressed message. * * @author Gary Russell + * @author Ngoc Nhan * @since 1.4.2 */ public abstract class AbstractDecompressingPostProcessor implements MessagePostProcessor, Ordered { @@ -115,9 +116,8 @@ public Message postProcessMessage(Message message) throws AmqpException { throw new AmqpIOException(e); } } - else { - return message; - } + + return message; } /** diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java index 9474d1b7c8..0651734b8c 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/support/postprocessor/DelegatingDecompressingPostProcessor.java @@ -98,22 +98,20 @@ public Message postProcessMessage(Message message) throws AmqpException { if (encoding == null) { return message; } - else { - int delimAt = encoding.indexOf(':'); - if (delimAt < 0) { - delimAt = encoding.indexOf(','); - } - if (delimAt > 0) { - encoding = encoding.substring(0, delimAt); - } - MessagePostProcessor decompressor = this.decompressors.get(encoding); - if (decompressor != null) { - return decompressor.postProcessMessage(message); - } - else { - return message; - } + + int delimAt = encoding.indexOf(':'); + if (delimAt < 0) { + delimAt = encoding.indexOf(','); + } + if (delimAt > 0) { + encoding = encoding.substring(0, delimAt); } + MessagePostProcessor decompressor = this.decompressors.get(encoding); + if (decompressor != null) { + return decompressor.postProcessMessage(message); + } + + return message; } } diff --git a/spring-amqp/src/main/java/org/springframework/amqp/utils/test/TestUtils.java b/spring-amqp/src/main/java/org/springframework/amqp/utils/test/TestUtils.java index 5934aa6a6a..f8c802e558 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/utils/test/TestUtils.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/utils/test/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2019 the original author or authors. + * Copyright 2013-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ * @author Iwein Fuld * @author Oleg Zhurakousky * @author Gary Russell + * @author Ngoc Nhan * @since 1.2 */ public final class TestUtils { @@ -47,13 +48,14 @@ public static Object getPropertyValue(Object root, String propertyPath) { value = accessor.getPropertyValue(tokens[i]); if (value != null) { accessor = new DirectFieldAccessor(value); + continue; } - else if (i == tokens.length - 1) { + + if (i == tokens.length - 1) { return null; } - else { - throw new IllegalArgumentException("intermediate property '" + tokens[i] + "' is null"); - } + + throw new IllegalArgumentException("intermediate property '" + tokens[i] + "' is null"); } return value; } diff --git a/spring-amqp/src/test/java/org/springframework/amqp/core/AddressTests.java b/spring-amqp/src/test/java/org/springframework/amqp/core/AddressTests.java index feaea573b2..17c24e4130 100644 --- a/spring-amqp/src/test/java/org/springframework/amqp/core/AddressTests.java +++ b/spring-amqp/src/test/java/org/springframework/amqp/core/AddressTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ * @author Mark Fisher * @author Artem Bilan * @author Gary Russell + * @author Ngoc Nhan */ public class AddressTests { @@ -100,6 +101,9 @@ public void testDirectReplyTo() { @Test public void testEquals() { assertThat(new Address("foo/bar")).isEqualTo(new Address("foo/bar")); + assertThat(new Address("foo", null)).isEqualTo(new Address("foo", null)); + assertThat(new Address(null, "bar")).isEqualTo(new Address(null, "bar")); + assertThat(new Address(null, null)).isEqualTo(new Address(null, null)); } } From 9873f4a162f4d4ed4af3d63883e3c226b5a838b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:10:19 +0000 Subject: [PATCH 054/111] Bump ch.qos.logback:logback-classic from 1.5.9 to 1.5.11 (#2864) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.9 to 1.5.11. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.9...v_1.5.11) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a1de461d86..c22be696e3 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ ext { junitJupiterVersion = '5.11.2' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' - logbackVersion = '1.5.9' + logbackVersion = '1.5.11' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-SNAPSHOT' From 0eb13d341aaba51a7d60c174ae2db0a92327e314 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:10:28 +0000 Subject: [PATCH 055/111] Bump com.github.spotbugs in the development-dependencies group (#2863) Bumps the development-dependencies group with 1 update: com.github.spotbugs. Updates `com.github.spotbugs` from 6.0.24 to 6.0.25 --- updated-dependencies: - dependency-name: com.github.spotbugs dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c22be696e3..463a995b9c 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' - id 'com.github.spotbugs' version '6.0.24' + id 'com.github.spotbugs' version '6.0.25' id 'io.freefair.aggregate-javadoc' version '8.10.2' } From dba2ab9037a8e24ad04e88c42ea914173e6b5a33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:10:47 +0000 Subject: [PATCH 056/111] Bump mockitoVersion from 5.14.1 to 5.14.2 (#2865) Bumps `mockitoVersion` from 5.14.1 to 5.14.2. Updates `org.mockito:mockito-core` from 5.14.1 to 5.14.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.1...v5.14.2) Updates `org.mockito:mockito-junit-jupiter` from 5.14.1 to 5.14.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.1...v5.14.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 463a995b9c..0376230c79 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ ext { micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-SNAPSHOT' - mockitoVersion = '5.14.1' + mockitoVersion = '5.14.2' rabbitmqStreamVersion = '0.17.0' rabbitmqVersion = '5.22.0' reactorVersion = '2024.0.0-SNAPSHOT' From f33075257ab082ce987a1799cef83ee390e781fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:10:53 +0000 Subject: [PATCH 057/111] Bump org.springframework.retry:spring-retry from 2.0.9 to 2.0.10 (#2866) Bumps [org.springframework.retry:spring-retry](https://github.com/spring-projects/spring-retry) from 2.0.9 to 2.0.10. - [Release notes](https://github.com/spring-projects/spring-retry/releases) - [Commits](https://github.com/spring-projects/spring-retry/compare/v2.0.9...v2.0.10) --- updated-dependencies: - dependency-name: org.springframework.retry:spring-retry dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0376230c79..350d32c759 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ ext { rabbitmqVersion = '5.22.0' reactorVersion = '2024.0.0-SNAPSHOT' springDataVersion = '2024.1.0-SNAPSHOT' - springRetryVersion = '2.0.9' + springRetryVersion = '2.0.10' springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.20.2' From 33da2a6158a49ff62a37cbebc5ac1e8ac5e73839 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 19 Oct 2024 05:58:29 -0400 Subject: [PATCH 058/111] Improve conditions in code * Reduce `else` condition and modernize switch pattern * Check condition after calling lock method * Some additional code clean up --- .../stream/producer/RabbitStreamTemplate.java | 88 +++++++++---------- ...itListenerAnnotationBeanPostProcessor.java | 5 +- .../rabbit/batch/SimpleBatchingStrategy.java | 12 ++- .../config/ListenerContainerFactoryBean.java | 15 ++-- .../config/ListenerContainerParser.java | 8 +- ...RetryOperationsInterceptorFactoryBean.java | 31 +++---- .../AbstractRoutingConnectionFactory.java | 4 +- .../connection/ConsumerChannelRegistry.java | 8 +- .../rabbit/connection/PendingConfirm.java | 5 +- .../PooledChannelConnectionFactory.java | 33 ++++--- .../PublisherCallbackChannelImpl.java | 33 ++++--- .../RabbitConnectionFactoryBean.java | 17 ++-- .../amqp/rabbit/connection/RabbitUtils.java | 52 +++++------ .../ThreadChannelConnectionFactory.java | 33 ++++--- .../rabbit/connection/WebFluxNodeLocator.java | 6 +- .../rabbit/listener/MicrometerHolder.java | 5 +- 16 files changed, 162 insertions(+), 193 deletions(-) diff --git a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java index 0751e7dbd3..8a42b52101 100644 --- a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java +++ b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 the original author or authors. + * Copyright 2021-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,6 +55,7 @@ * * @author Gary Russell * @author Christian Tzolov + * @author Ngoc Nhan * @since 2.4 * */ @@ -107,29 +108,31 @@ public RabbitStreamTemplate(Environment environment, String streamName) { private Producer createOrGetProducer() { - this.lock.lock(); - try { - if (this.producer == null) { - ProducerBuilder builder = this.environment.producerBuilder(); - if (this.superStreamRouting == null) { - builder.stream(this.streamName); - } - else { - builder.superStream(this.streamName) - .routing(this.superStreamRouting); - } - this.producerCustomizer.accept(this.beanName, builder); - this.producer = builder.build(); - if (!this.streamConverterSet) { - ((DefaultStreamMessageConverter) this.streamConverter).setBuilderSupplier( - () -> this.producer.messageBuilder()); + if (this.producer == null) { + this.lock.lock(); + try { + if (this.producer == null) { + ProducerBuilder builder = this.environment.producerBuilder(); + if (this.superStreamRouting == null) { + builder.stream(this.streamName); + } + else { + builder.superStream(this.streamName) + .routing(this.superStreamRouting); + } + this.producerCustomizer.accept(this.beanName, builder); + this.producer = builder.build(); + if (!this.streamConverterSet) { + ((DefaultStreamMessageConverter) this.streamConverter).setBuilderSupplier( + () -> this.producer.messageBuilder()); + } } } - return this.producer; - } - finally { - this.lock.unlock(); + finally { + this.lock.unlock(); + } } + return this.producer; } @Override @@ -305,24 +308,13 @@ private ConfirmationHandler handleConfirm(CompletableFuture future, Obs } else { int code = confStatus.getCode(); - String errorMessage; - switch (code) { - case Constants.CODE_MESSAGE_ENQUEUEING_FAILED: - errorMessage = "Message Enqueueing Failed"; - break; - case Constants.CODE_PRODUCER_CLOSED: - errorMessage = "Producer Closed"; - break; - case Constants.CODE_PRODUCER_NOT_AVAILABLE: - errorMessage = "Producer Not Available"; - break; - case Constants.CODE_PUBLISH_CONFIRM_TIMEOUT: - errorMessage = "Publish Confirm Timeout"; - break; - default: - errorMessage = "Unknown code: " + code; - break; - } + String errorMessage = switch (code) { + case Constants.CODE_MESSAGE_ENQUEUEING_FAILED -> "Message Enqueueing Failed"; + case Constants.CODE_PRODUCER_CLOSED -> "Producer Closed"; + case Constants.CODE_PRODUCER_NOT_AVAILABLE -> "Producer Not Available"; + case Constants.CODE_PUBLISH_CONFIRM_TIMEOUT -> "Publish Confirm Timeout"; + default -> "Unknown code: " + code; + }; StreamSendException ex = new StreamSendException(errorMessage, code); observation.error(ex); observation.stop(); @@ -339,15 +331,17 @@ private ConfirmationHandler handleConfirm(CompletableFuture future, Obs */ @Override public void close() { - this.lock.lock(); - try { - if (this.producer != null) { - this.producer.close(); - this.producer = null; + if (this.producer != null) { + this.lock.lock(); + try { + if (this.producer != null) { + this.producer.close(); + this.producer = null; + } + } + finally { + this.lock.unlock(); } - } - finally { - this.lock.unlock(); } } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java index 2c1ce24447..e22e1b3860 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/RabbitListenerAnnotationBeanPostProcessor.java @@ -76,6 +76,7 @@ import org.springframework.context.expression.StandardBeanExpressionResolver; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.convert.ConversionService; @@ -357,7 +358,7 @@ else if (source instanceof Method method) { } return !name.contains("$MockitoMock$"); }) - .map(ann -> ann.synthesize()) + .map(MergedAnnotation::synthesize) .collect(Collectors.toList()); } @@ -893,7 +894,7 @@ private void addToMap(Map map, String key, Object value, Class= this.bufferLimit) { + if (this.currentSize >= this.bufferLimit) { // release immediately, we're already over the limit return new Date(); } - else { - return new Date(System.currentTimeMillis() + this.timeout); - } + + return new Date(System.currentTimeMillis() + this.timeout); } @Override @@ -122,9 +121,8 @@ public Collection releaseBatches() { if (batch == null) { return Collections.emptyList(); } - else { - return Collections.singletonList(batch); - } + + return Collections.singletonList(batch); } private MessageBatch doReleaseBatch() { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java index c919105ea1..b2bc26fb8a 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerFactoryBean.java @@ -575,14 +575,13 @@ private AbstractMessageListenerContainer createContainer() { .acceptIfNotNull(this.retryDeclarationInterval, container::setRetryDeclarationInterval); return container; } - else { - DirectMessageListenerContainer container = new DirectMessageListenerContainer(this.connectionFactory); - JavaUtils.INSTANCE - .acceptIfNotNull(this.consumersPerQueue, container::setConsumersPerQueue) - .acceptIfNotNull(this.taskScheduler, container::setTaskScheduler) - .acceptIfNotNull(this.monitorInterval, container::setMonitorInterval); - return container; - } + + DirectMessageListenerContainer container = new DirectMessageListenerContainer(this.connectionFactory); + JavaUtils.INSTANCE + .acceptIfNotNull(this.consumersPerQueue, container::setConsumersPerQueue) + .acceptIfNotNull(this.taskScheduler, container::setTaskScheduler) + .acceptIfNotNull(this.monitorInterval, container::setMonitorInterval); + return container; } @Override diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java index fce31f9935..71acf60981 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/ListenerContainerParser.java @@ -101,8 +101,8 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { } List childElements = DomUtils.getChildElementsByTagName(element, LISTENER_ELEMENT); - for (int i = 0; i < childElements.size(); i++) { - parseListener(childElements.get(i), element, parserContext, containerList); + for (Element childElement : childElements) { + parseListener(childElement, element, parserContext, containerList); } parserContext.popAndRegisterContainingComponent(); @@ -190,8 +190,8 @@ private void parseListener(Element listenerEle, Element containerEle, ParserCont else { String[] names = StringUtils.commaDelimitedListToStringArray(queues); List values = new ManagedList<>(); - for (int i = 0; i < names.length; i++) { - values.add(new RuntimeBeanReference(names[i].trim())); + for (String name : names) { + values.add(new RuntimeBeanReference(name.trim())); } containerDef.getPropertyValues().add("queues", values); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java index 3aa40f94ef..4a468f750f 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,12 +27,14 @@ import org.springframework.amqp.rabbit.retry.MessageKeyGenerator; import org.springframework.amqp.rabbit.retry.MessageRecoverer; import org.springframework.amqp.rabbit.retry.NewMessageIdentifier; +import org.springframework.lang.Nullable; import org.springframework.retry.RetryOperations; import org.springframework.retry.interceptor.MethodArgumentsKeyGenerator; import org.springframework.retry.interceptor.MethodInvocationRecoverer; import org.springframework.retry.interceptor.NewMethodArgumentsIdentifier; import org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor; import org.springframework.retry.support.RetryTemplate; +import org.springframework.util.Assert; /** * Convenient factory bean for creating a stateful retry interceptor for use in a message listener container, giving you @@ -47,6 +49,7 @@ * * @author Dave Syer * @author Gary Russell + * @author Ngoc Nhan * * @see RetryOperations#execute(org.springframework.retry.RetryCallback, org.springframework.retry.RecoveryCallback, * org.springframework.retry.RetryState) @@ -90,9 +93,8 @@ private NewMethodArgumentsIdentifier createNewItemIdentifier() { if (StatefulRetryOperationsInterceptorFactoryBean.this.newMessageIdentifier == null) { return !message.getMessageProperties().isRedelivered(); } - else { - return StatefulRetryOperationsInterceptorFactoryBean.this.newMessageIdentifier.isNew(message); - } + + return StatefulRetryOperationsInterceptorFactoryBean.this.newMessageIdentifier.isNew(message); }; } @@ -120,6 +122,7 @@ else if (arg instanceof List && messageRecoverer instanceof MessageBatchRecovere private MethodArgumentsKeyGenerator createKeyGenerator() { return args -> { Message message = argToMessage(args); + Assert.notNull(message, "The 'args' must not convert to null"); if (StatefulRetryOperationsInterceptorFactoryBean.this.messageKeyGenerator == null) { String messageId = message.getMessageProperties().getMessageId(); if (messageId == null && message.getMessageProperties().isRedelivered()) { @@ -127,23 +130,20 @@ private MethodArgumentsKeyGenerator createKeyGenerator() { } return messageId; } - else { - return StatefulRetryOperationsInterceptorFactoryBean.this.messageKeyGenerator.getKey(message); - } + return StatefulRetryOperationsInterceptorFactoryBean.this.messageKeyGenerator.getKey(message); }; } - @SuppressWarnings("unchecked") + @Nullable private Message argToMessage(Object[] args) { Object arg = args[1]; - Message message = null; if (arg instanceof Message msg) { - message = msg; + return msg; } - else if (arg instanceof List) { - message = ((List) arg).get(0); + if (arg instanceof List list) { + return (Message) list.get(0); } - return message; + return null; } @Override @@ -151,9 +151,4 @@ public Class getObjectType() { return StatefulRetryOperationsInterceptor.class; } - @Override - public boolean isSingleton() { - return true; - } - } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java index b4fed509e0..be70f77cc5 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractRoutingConnectionFactory.java @@ -69,7 +69,7 @@ public void setTargetConnectionFactories(Map targetCo Assert.noNullElements(targetConnectionFactories.values().toArray(), "'targetConnectionFactories' cannot have null values."); this.targetConnectionFactories.putAll(targetConnectionFactories); - targetConnectionFactories.values().stream().forEach(cf -> checkConfirmsAndReturns(cf)); + targetConnectionFactories.values().forEach(this::checkConfirmsAndReturns); } /** @@ -293,7 +293,7 @@ public void destroy() { @Override public void resetConnection() { - this.targetConnectionFactories.values().forEach(factory -> factory.resetConnection()); + this.targetConnectionFactories.values().forEach(ConnectionFactory::resetConnection); this.defaultTargetConnectionFactory.resetConnection(); } diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java index d1a82f4d87..e72c338b04 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ConsumerChannelRegistry.java @@ -84,11 +84,9 @@ public static void unRegisterConsumerChannel() { @Nullable public static Channel getConsumerChannel() { ChannelHolder channelHolder = consumerChannel.get(); - Channel channel = null; - if (channelHolder != null) { - channel = channelHolder.getChannel(); - } - return channel; + return channelHolder != null + ? channelHolder.getChannel() + : null; } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PendingConfirm.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PendingConfirm.java index 95c71fe744..5aa67760c9 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PendingConfirm.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PendingConfirm.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ * expired. It also holds {@link CorrelationData} for * the client to correlate a confirm with a sent message. * @author Gary Russell + * @author Ngoc Nhan * @since 1.0.1 * */ @@ -115,7 +116,7 @@ public void setReturned(boolean isReturned) { * @since 2.2.10 */ public boolean waitForReturnIfNeeded() throws InterruptedException { - return this.returned ? this.latch.await(RETURN_CALLBACK_TIMEOUT, TimeUnit.SECONDS) : true; + return !this.returned || this.latch.await(RETURN_CALLBACK_TIMEOUT, TimeUnit.SECONDS); } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PooledChannelConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PooledChannelConnectionFactory.java index a458be72ab..321c8925ab 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PooledChannelConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PooledChannelConnectionFactory.java @@ -55,6 +55,7 @@ * @author Gary Russell * @author Leonardo Ferreira * @author Christian Tzolov + * @author Ngoc Nhan * @since 2.3 * */ @@ -255,23 +256,21 @@ private Channel createProxy(Channel channel, boolean transacted) { Advice advice = (MethodInterceptor) invocation -> { String method = invocation.getMethod().getName(); - switch (method) { - case "close": - handleClose(channel, transacted, proxy); - return null; - case "getTargetChannel": - return channel; - case "isTransactional": - return transacted; - case "confirmSelect": - confirmSelected.set(true); - return channel.confirmSelect(); - case "isConfirmSelected": - return confirmSelected.get(); - case "isPublisherConfirms": - return false; - } - return null; + return switch (method) { + case "close" -> { + handleClose(channel, transacted, proxy); + yield null; + } + case "getTargetChannel" -> channel; + case "isTransactional" -> transacted; + case "confirmSelect" -> { + confirmSelected.set(true); + yield channel.confirmSelect(); + } + case "isConfirmSelected" -> confirmSelected.get(); + case "isPublisherConfirms" -> false; + default -> null; + }; }; NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(advice); advisor.addMethodName("close"); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java index b8ee5e29dd..74fb85bc95 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/PublisherCallbackChannelImpl.java @@ -922,27 +922,26 @@ public Collection expire(Listener listener, long cutoffTime) { try { SortedMap pendingConfirmsForListener = this.pendingConfirms.get(listener); if (pendingConfirmsForListener == null) { - return Collections.emptyList(); + return Collections.emptyList(); } - else { - List expired = new ArrayList<>(); - Iterator> iterator = pendingConfirmsForListener.entrySet().iterator(); - while (iterator.hasNext()) { - PendingConfirm pendingConfirm = iterator.next().getValue(); - if (pendingConfirm.getTimestamp() < cutoffTime) { - expired.add(pendingConfirm); - iterator.remove(); - CorrelationData correlationData = pendingConfirm.getCorrelationData(); - if (correlationData != null && StringUtils.hasText(correlationData.getId())) { - this.pendingReturns.remove(correlationData.getId()); // NOSONAR never null - } - } - else { - break; + + List expired = new ArrayList<>(); + Iterator> iterator = pendingConfirmsForListener.entrySet().iterator(); + while (iterator.hasNext()) { + PendingConfirm pendingConfirm = iterator.next().getValue(); + if (pendingConfirm.getTimestamp() < cutoffTime) { + expired.add(pendingConfirm); + iterator.remove(); + CorrelationData correlationData = pendingConfirm.getCorrelationData(); + if (correlationData != null && StringUtils.hasText(correlationData.getId())) { + this.pendingReturns.remove(correlationData.getId()); // NOSONAR never null } } - return expired; + else { + break; + } } + return expired; } finally { this.lock.unlock(); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java index d12361ee1d..779bdef7c9 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,6 +79,7 @@ * @author Hareendran * @author Dominique Villard * @author Zachary DeLuca + * @author Ngoc Nhan * * @since 1.4 */ @@ -360,12 +361,11 @@ protected String getKeyStoreType() { if (this.keyStoreType == null && this.sslProperties.getProperty(KEY_STORE_TYPE) == null) { return KEY_STORE_DEFAULT_TYPE; } - else if (this.keyStoreType != null) { + if (this.keyStoreType != null) { return this.keyStoreType; } - else { - return this.sslProperties.getProperty(KEY_STORE_TYPE); - } + + return this.sslProperties.getProperty(KEY_STORE_TYPE); } /** @@ -389,12 +389,11 @@ protected String getTrustStoreType() { if (this.trustStoreType == null && this.sslProperties.getProperty(TRUST_STORE_TYPE) == null) { return TRUST_STORE_DEFAULT_TYPE; } - else if (this.trustStoreType != null) { + if (this.trustStoreType != null) { return this.trustStoreType; } - else { - return this.sslProperties.getProperty(TRUST_STORE_TYPE); - } + + return this.sslProperties.getProperty(TRUST_STORE_TYPE); } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java index 1d0c1609f8..e135d365a2 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitUtils.java @@ -228,12 +228,7 @@ public static void setPhysicalCloseRequired(Channel channel, boolean b) { */ public static boolean isPhysicalCloseRequired() { Boolean mustClose = physicalCloseRequired.get(); - if (mustClose == null) { - return false; - } - else { - return mustClose; - } + return mustClose != null && mustClose; } /** @@ -322,13 +317,12 @@ public static boolean isMismatchedQueueArgs(Exception e) { if (sig == null) { return false; } - else { - Method shutdownReason = sig.getReason(); - return shutdownReason instanceof AMQP.Channel.Close closeReason - && AMQP.PRECONDITION_FAILED == closeReason.getReplyCode() - && closeReason.getClassId() == QUEUE_CLASS_ID_50 - && closeReason.getMethodId() == DECLARE_METHOD_ID_10; - } + + Method shutdownReason = sig.getReason(); + return shutdownReason instanceof AMQP.Channel.Close closeReason + && AMQP.PRECONDITION_FAILED == closeReason.getReplyCode() + && closeReason.getClassId() == QUEUE_CLASS_ID_50 + && closeReason.getMethodId() == DECLARE_METHOD_ID_10; } /** @@ -352,13 +346,12 @@ public static boolean isExchangeDeclarationFailure(Exception e) { if (sig == null) { return false; } - else { - Method shutdownReason = sig.getReason(); - return shutdownReason instanceof AMQP.Channel.Close closeReason - && AMQP.PRECONDITION_FAILED == closeReason.getReplyCode() - && closeReason.getClassId() == EXCHANGE_CLASS_ID_40 - && closeReason.getMethodId() == DECLARE_METHOD_ID_10; - } + + Method shutdownReason = sig.getReason(); + return shutdownReason instanceof AMQP.Channel.Close closeReason + && AMQP.PRECONDITION_FAILED == closeReason.getReplyCode() + && closeReason.getClassId() == EXCHANGE_CLASS_ID_40 + && closeReason.getMethodId() == DECLARE_METHOD_ID_10; } /** @@ -395,18 +388,13 @@ public static int getMaxFrame(ConnectionFactory connectionFactory) { public static SaslConfig stringToSaslConfig(String saslConfig, com.rabbitmq.client.ConnectionFactory connectionFactory) { - switch (saslConfig) { - case "DefaultSaslConfig.PLAIN": - return DefaultSaslConfig.PLAIN; - case "DefaultSaslConfig.EXTERNAL": - return DefaultSaslConfig.EXTERNAL; - case "JDKSaslConfig": - return new JDKSaslConfig(connectionFactory); - case "CRDemoSaslConfig": - return new CRDemoMechanism.CRDemoSaslConfig(); - default: - throw new IllegalStateException("Unrecognized SaslConfig: " + saslConfig); - } + return switch (saslConfig) { + case "DefaultSaslConfig.PLAIN" -> DefaultSaslConfig.PLAIN; + case "DefaultSaslConfig.EXTERNAL" -> DefaultSaslConfig.EXTERNAL; + case "JDKSaslConfig" -> new JDKSaslConfig(connectionFactory); + case "CRDemoSaslConfig" -> new CRDemoMechanism.CRDemoSaslConfig(); + default -> throw new IllegalStateException("Unrecognized SaslConfig: " + saslConfig); + }; } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java index b9d371e683..8097eed059 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/ThreadChannelConnectionFactory.java @@ -24,7 +24,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; @@ -196,8 +195,8 @@ public void destroy() { this.logger.warn("Unclaimed context switches from threads:" + this.switchesInProgress.values() .stream() - .map(t -> t.getName()) - .collect(Collectors.toList())); + .map(Thread::getName) + .toList()); } this.contextSwitches.clear(); this.switchesInProgress.clear(); @@ -319,23 +318,21 @@ private Channel createProxy(Channel channel, boolean transactional) { Advice advice = (MethodInterceptor) invocation -> { String method = invocation.getMethod().getName(); - switch (method) { - case "close": + return switch (method) { + case "close" -> { handleClose(channel, transactional); - return null; - case "getTargetChannel": - return channel; - case "isTransactional": - return transactional; - case "confirmSelect": + yield null; + } + case "getTargetChannel" -> channel; + case "isTransactional" -> transactional; + case "confirmSelect" -> { confirmSelected.set(true); - return channel.confirmSelect(); - case "isConfirmSelected": - return confirmSelected.get(); - case "isPublisherConfirms": - return false; - } - return null; + yield channel.confirmSelect(); + } + case "isConfirmSelected" -> confirmSelected.get(); + case "isPublisherConfirms" -> false; + default -> null; + }; }; NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(advice); advisor.addMethodName("close"); diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/WebFluxNodeLocator.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/WebFluxNodeLocator.java index 6c10164474..75acd71e81 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/WebFluxNodeLocator.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/WebFluxNodeLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ * A {@link NodeLocator} using the Spring WebFlux {@link WebClient}. * * @author Gary Russell + * @author Ngoc Nhan * @since 2.4.8 * */ @@ -46,14 +47,13 @@ public Map restCall(WebClient client, String baseUri, String vho URI uri = new URI(baseUri) .resolve("/api/queues/" + UriUtils.encodePathSegment(vhost, StandardCharsets.UTF_8) + "/" + queue); - HashMap queueInfo = client.get() + return client.get() .uri(uri) .accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(new ParameterizedTypeReference>() { }) .block(Duration.ofSeconds(10)); // NOSONAR magic# - return queueInfo != null ? queueInfo : null; } /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MicrometerHolder.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MicrometerHolder.java index 72d06e140f..5cd536329f 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MicrometerHolder.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/MicrometerHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 the original author or authors. + * Copyright 2022-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ * Abstraction to avoid hard reference to Micrometer. * * @author Gary Russell + * @author Ngoc Nhan * @since 2.4.6 * */ @@ -95,7 +96,7 @@ private Timer buildTimer(String aListenerId, String result, String queue, String .tag("result", result) .tag("exception", exception); if (this.tags != null && !this.tags.isEmpty()) { - this.tags.forEach((key, value) -> builder.tag(key, value)); + this.tags.forEach(builder::tag); } Timer registeredTimer = builder.register(this.registry); this.timers.put(queue + exception, registeredTimer); From 24fcddb104747ed2e3937e3502c219148604ef32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:49:37 +0000 Subject: [PATCH 059/111] Bump org.junit:junit-bom from 5.11.2 to 5.11.3 (#2875) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.2 to 5.11.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.2...r5.11.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 350d32c759..6a5237aeed 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ ext { jacksonBomVersion = '2.18.0' jaywayJsonPathVersion = '2.9.0' junit4Version = '4.13.2' - junitJupiterVersion = '5.11.2' + junitJupiterVersion = '5.11.3' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' logbackVersion = '1.5.11' From 94956d6f73746085996c5e210741b9467ab00b40 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 21 Oct 2024 13:06:22 -0400 Subject: [PATCH 060/111] Upgrade deps; including Antora NodeJS modules * Prepare for release * Remove redundant `org.apache.commons:commons-compress` dep. Managed now transitively by the `com.rabbitmq:stream-client` library --- build.gradle | 24 +++++++++++------------- src/reference/antora/antora-playbook.yml | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 6a5237aeed..0d2197b5af 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,6 @@ ext { assertjVersion = '3.26.3' assertkVersion = '0.28.1' awaitilityVersion = '4.2.2' - commonsCompressVersion = '1.27.1' commonsHttpClientVersion = '5.4' commonsPoolVersion = '2.12.0' hamcrestVersion = '3.0' @@ -61,15 +60,15 @@ ext { log4jVersion = '2.24.1' logbackVersion = '1.5.11' micrometerDocsVersion = '1.0.4' - micrometerVersion = '1.14.0-SNAPSHOT' - micrometerTracingVersion = '1.4.0-SNAPSHOT' + micrometerVersion = '1.14.0-RC1' + micrometerTracingVersion = '1.4.0-RC1' mockitoVersion = '5.14.2' - rabbitmqStreamVersion = '0.17.0' + rabbitmqStreamVersion = '0.18.0' rabbitmqVersion = '5.22.0' - reactorVersion = '2024.0.0-SNAPSHOT' - springDataVersion = '2024.1.0-SNAPSHOT' + reactorVersion = '2024.0.0-RC1' + springDataVersion = '2024.1.0-RC1' springRetryVersion = '2.0.10' - springVersion = '6.2.0-SNAPSHOT' + springVersion = '6.2.0-RC2' testcontainersVersion = '1.20.2' javaProjects = subprojects - project(':spring-amqp-bom') @@ -80,11 +79,11 @@ antora { playbook = file('src/reference/antora/antora-playbook.yml') options = ['to-dir' : project.layout.buildDirectory.dir('site').get().toString(), clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true] dependencies = [ - '@antora/atlas-extension': '1.0.0-alpha.1', - '@antora/collector-extension': '1.0.0-alpha.3', - '@asciidoctor/tabs': '1.0.0-beta.3', - '@springio/antora-extensions': '1.11.1', - '@springio/asciidoctor-extensions': '1.0.0-alpha.10', + '@antora/atlas-extension': '1.0.0-alpha.2', + '@antora/collector-extension': '1.0.0-beta.3', + '@asciidoctor/tabs': '1.0.0-beta.6', + '@springio/antora-extensions': '1.14.2', + '@springio/asciidoctor-extensions': '1.0.0-alpha.14', ] } @@ -466,7 +465,6 @@ project('spring-rabbit-stream') { testRuntimeOnly 'com.fasterxml.jackson.core:jackson-databind' testRuntimeOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml' testRuntimeOnly 'com.fasterxml.jackson.module:jackson-module-kotlin' - testRuntimeOnly "org.apache.commons:commons-compress:$commonsCompressVersion" testImplementation "org.testcontainers:rabbitmq" testImplementation "org.testcontainers:junit-jupiter" diff --git a/src/reference/antora/antora-playbook.yml b/src/reference/antora/antora-playbook.yml index 333dfc2fb5..8397e13ecc 100644 --- a/src/reference/antora/antora-playbook.yml +++ b/src/reference/antora/antora-playbook.yml @@ -32,4 +32,4 @@ runtime: format: pretty ui: bundle: - url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.15/ui-bundle.zip + url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.17/ui-bundle.zip From b8a0f7acfc5144d9d2b680addae1968711f8fbee Mon Sep 17 00:00:00 2001 From: Spring Builds Date: Mon, 21 Oct 2024 18:32:09 +0000 Subject: [PATCH 061/111] [artifactory-release] Release version 3.2.0-RC1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6bc0422ab1..70c15ef48c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.2.0-SNAPSHOT +version=3.2.0-RC1 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8 org.gradle.daemon=true org.gradle.caching=true From b1c6893e3103ce83b0f937aba2601f36f7a54f75 Mon Sep 17 00:00:00 2001 From: Spring Builds Date: Mon, 21 Oct 2024 18:32:11 +0000 Subject: [PATCH 062/111] [artifactory-release] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 70c15ef48c..6bc0422ab1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=3.2.0-RC1 +version=3.2.0-SNAPSHOT org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8 org.gradle.daemon=true org.gradle.caching=true From f150bf531ae9cf0f8ae7e278889e7f9b084ffee6 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 21 Oct 2024 17:47:49 -0400 Subject: [PATCH 063/111] Make `RabbitStreamTemplate.producer` as `volatile` --- .../rabbit/stream/producer/RabbitStreamTemplate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java index 8a42b52101..a0bde53ad2 100644 --- a/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java +++ b/spring-rabbit-stream/src/main/java/org/springframework/rabbit/stream/producer/RabbitStreamTemplate.java @@ -79,8 +79,6 @@ public class RabbitStreamTemplate implements RabbitStreamOperations, Application private boolean streamConverterSet; - private Producer producer; - private String beanName; private ProducerCustomizer producerCustomizer = (name, builder) -> { }; @@ -90,10 +88,12 @@ public class RabbitStreamTemplate implements RabbitStreamOperations, Application @Nullable private RabbitStreamTemplateObservationConvention observationConvention; - private volatile boolean observationRegistryObtained; - private ObservationRegistry observationRegistry; + private volatile Producer producer; + + private volatile boolean observationRegistryObtained; + /** * Construct an instance with the provided {@link Environment}. * @param environment the environment. From c321e948903f42bcaa3e8c1a78471fb71a4bf853 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 22 Oct 2024 11:50:32 -0400 Subject: [PATCH 064/111] Increase `await()` timeout to 30 sec for `AsyncRabbitTemplateTests` --- .../amqp/rabbit/AsyncRabbitTemplateTests.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java index e054a7abab..b0cb6d92c1 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/AsyncRabbitTemplateTests.java @@ -22,6 +22,7 @@ import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; +import java.time.Duration; import java.util.Map; import java.util.UUID; import java.util.concurrent.CancellationException; @@ -35,6 +36,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.amqp.core.Address; @@ -91,6 +94,11 @@ public class AsyncRabbitTemplateTests { private final Message fooMessage = new SimpleMessageConverter().toMessage("foo", new MessageProperties()); + @BeforeAll + static void setup() { + Awaitility.setDefaultTimeout(Duration.ofSeconds(30)); + } + @Test public void testConvert1Arg() throws Exception { final AtomicBoolean mppCalled = new AtomicBoolean(); From b391195b50518e2add0f3d2d225db57b035bbaf4 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 23 Oct 2024 14:36:30 -0400 Subject: [PATCH 065/111] Upgrade reusable WFs from `main` to `v4` **Auto-cherry-pick to `3.1.x`** --- .github/workflows/announce-milestone-planning.yml | 2 +- .github/workflows/merge-dependabot-pr.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/announce-milestone-planning.yml b/.github/workflows/announce-milestone-planning.yml index e4e90710c9..1075304cd1 100644 --- a/.github/workflows/announce-milestone-planning.yml +++ b/.github/workflows/announce-milestone-planning.yml @@ -6,6 +6,6 @@ on: jobs: announce-milestone-planning: - uses: spring-io/spring-github-workflows/.github/workflows/spring-announce-milestone-planning.yml@main + uses: spring-io/spring-github-workflows/.github/workflows/spring-announce-milestone-planning.yml@v4 secrets: SPRING_RELEASE_CHAT_WEBHOOK_URL: ${{ secrets.SPRING_RELEASE_GCHAT_WEBHOOK_URL }} \ No newline at end of file diff --git a/.github/workflows/merge-dependabot-pr.yml b/.github/workflows/merge-dependabot-pr.yml index 0b1d927d8e..44a74e507b 100644 --- a/.github/workflows/merge-dependabot-pr.yml +++ b/.github/workflows/merge-dependabot-pr.yml @@ -12,7 +12,7 @@ jobs: merge-dependabot-pr: permissions: write-all - uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@main + uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@v4 with: mergeArguments: --auto --squash autoMergeSnapshots: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90f17f1609..40dfecca8b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: contents: write issues: write - uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@main + uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@v4 secrets: GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} From e48445af516dcf12697d1cac994c8ffdece6b8e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:26:09 +0000 Subject: [PATCH 066/111] Bump spring-io/spring-github-workflows (#2877) Bumps the development-dependencies group with 1 update: [spring-io/spring-github-workflows](https://github.com/spring-io/spring-github-workflows). Updates `spring-io/spring-github-workflows` from 3 to 4 - [Release notes](https://github.com/spring-io/spring-github-workflows/releases) - [Commits](https://github.com/spring-io/spring-github-workflows/compare/v3...v4) --- updated-dependencies: - dependency-name: spring-io/spring-github-workflows dependency-type: direct:production update-type: version-update:semver-major dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/auto-cherry-pick.yml | 2 +- .github/workflows/backport-issue.yml | 2 +- .github/workflows/deploy-docs.yml | 2 +- .github/workflows/pr-build.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-cherry-pick.yml b/.github/workflows/auto-cherry-pick.yml index ad08e22428..bb476cb186 100644 --- a/.github/workflows/auto-cherry-pick.yml +++ b/.github/workflows/auto-cherry-pick.yml @@ -8,6 +8,6 @@ on: jobs: cherry-pick-commit: - uses: spring-io/spring-github-workflows/.github/workflows/spring-cherry-pick.yml@v3 + uses: spring-io/spring-github-workflows/.github/workflows/spring-cherry-pick.yml@v4 secrets: GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/backport-issue.yml b/.github/workflows/backport-issue.yml index 68de1977f1..b329f47c85 100644 --- a/.github/workflows/backport-issue.yml +++ b/.github/workflows/backport-issue.yml @@ -7,6 +7,6 @@ on: jobs: backport-issue: - uses: spring-io/spring-github-workflows/.github/workflows/spring-backport-issue.yml@v3 + uses: spring-io/spring-github-workflows/.github/workflows/spring-backport-issue.yml@v4 secrets: GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 5726382e2f..20e3d9067f 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -16,4 +16,4 @@ permissions: jobs: dispatch-docs-build: if: github.repository_owner == 'spring-projects' - uses: spring-io/spring-github-workflows/.github/workflows/spring-dispatch-docs-build.yml@v3 + uses: spring-io/spring-github-workflows/.github/workflows/spring-dispatch-docs-build.yml@v4 diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index b03b5bf93d..7f728da35c 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -8,4 +8,4 @@ on: jobs: build-pull-request: - uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@v3 + uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@v4 From 52c874ea460b6751b28abbd189eed844a16ce18c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:57:34 +0000 Subject: [PATCH 067/111] Bump io.micrometer:micrometer-bom from 1.14.0-RC1 to 1.14.0-SNAPSHOT (#2884) Bumps [io.micrometer:micrometer-bom](https://github.com/micrometer-metrics/micrometer) from 1.14.0-RC1 to 1.14.0-SNAPSHOT. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/commits) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0d2197b5af..cb13f52e8a 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ ext { log4jVersion = '2.24.1' logbackVersion = '1.5.11' micrometerDocsVersion = '1.0.4' - micrometerVersion = '1.14.0-RC1' + micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-RC1' mockitoVersion = '5.14.2' rabbitmqStreamVersion = '0.18.0' From 0d556305320c652f4a93991a7c98f5bfe8e168c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:58:23 +0000 Subject: [PATCH 068/111] Bump io.projectreactor:reactor-bom (#2878) Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2024.0.0-RC1 to 2024.0.0-SNAPSHOT. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/commits) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cb13f52e8a..0b20beefdb 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ ext { mockitoVersion = '5.14.2' rabbitmqStreamVersion = '0.18.0' rabbitmqVersion = '5.22.0' - reactorVersion = '2024.0.0-RC1' + reactorVersion = '2024.0.0-SNAPSHOT' springDataVersion = '2024.1.0-RC1' springRetryVersion = '2.0.10' springVersion = '6.2.0-RC2' From 6622c079cb7a3bad7d8e5e0f399f05e77cf85bb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:58:35 +0000 Subject: [PATCH 069/111] Bump ch.qos.logback:logback-classic from 1.5.11 to 1.5.12 (#2882) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.11 to 1.5.12. - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.11...v_1.5.12) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0b20beefdb..12453f2cea 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ ext { junitJupiterVersion = '5.11.3' kotlinCoroutinesVersion = '1.8.1' log4jVersion = '2.24.1' - logbackVersion = '1.5.11' + logbackVersion = '1.5.12' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' micrometerTracingVersion = '1.4.0-RC1' From 555a75cc13f21ce6c6bba6cadc14d484de515f28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 02:58:49 +0000 Subject: [PATCH 070/111] Bump org.testcontainers:testcontainers-bom from 1.20.2 to 1.20.3 (#2883) Bumps [org.testcontainers:testcontainers-bom](https://github.com/testcontainers/testcontainers-java) from 1.20.2 to 1.20.3. - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.20.2...1.20.3) --- updated-dependencies: - dependency-name: org.testcontainers:testcontainers-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 12453f2cea..9213581551 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ ext { springDataVersion = '2024.1.0-RC1' springRetryVersion = '2.0.10' springVersion = '6.2.0-RC2' - testcontainersVersion = '1.20.2' + testcontainersVersion = '1.20.3' javaProjects = subprojects - project(':spring-amqp-bom') } From a7da5966765e0ae91cb30d3e336c3960c1685d1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 03:00:21 +0000 Subject: [PATCH 071/111] Bump io.micrometer:micrometer-tracing-bom (#2879) Bumps [io.micrometer:micrometer-tracing-bom](https://github.com/micrometer-metrics/tracing) from 1.4.0-RC1 to 1.4.0-SNAPSHOT. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/commits) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9213581551..1fb77fe485 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ ext { logbackVersion = '1.5.12' micrometerDocsVersion = '1.0.4' micrometerVersion = '1.14.0-SNAPSHOT' - micrometerTracingVersion = '1.4.0-RC1' + micrometerTracingVersion = '1.4.0-SNAPSHOT' mockitoVersion = '5.14.2' rabbitmqStreamVersion = '0.18.0' rabbitmqVersion = '5.22.0' From 88a1e6b5aef8567a4ed77d777cd2262c3bbdc901 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 03:01:37 +0000 Subject: [PATCH 072/111] Bump org.springframework.data:spring-data-bom (#2881) Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.0-RC1 to 2024.1.0-SNAPSHOT. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/commits) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1fb77fe485..ccf0d841b6 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ ext { rabbitmqStreamVersion = '0.18.0' rabbitmqVersion = '5.22.0' reactorVersion = '2024.0.0-SNAPSHOT' - springDataVersion = '2024.1.0-RC1' + springDataVersion = '2024.1.0-SNAPSHOT' springRetryVersion = '2.0.10' springVersion = '6.2.0-RC2' testcontainersVersion = '1.20.3' From 1f0a6d3d7ec41da471b79fe921dfca1390baf369 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 03:02:00 +0000 Subject: [PATCH 073/111] Bump org.springframework:spring-framework-bom (#2880) Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.0-RC2 to 6.2.0-SNAPSHOT. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/commits) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ccf0d841b6..096b2900aa 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ ext { reactorVersion = '2024.0.0-SNAPSHOT' springDataVersion = '2024.1.0-SNAPSHOT' springRetryVersion = '2.0.10' - springVersion = '6.2.0-RC2' + springVersion = '6.2.0-SNAPSHOT' testcontainersVersion = '1.20.3' javaProjects = subprojects - project(':spring-amqp-bom') From de60344b89cec4fec1a0976b0ff2cbc5cdfb81da Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 30 Oct 2024 15:41:26 -0400 Subject: [PATCH 074/111] Fix mentioning of the deprecated `ListenableFuture` * Some rearranging fixes for `nav.adoc` and `appendix\previous-whats-new` dir --- src/reference/antora/modules/ROOT/nav.adoc | 3 --- .../modules/ROOT/pages/amqp/request-reply.adoc | 2 -- .../previous-whats-new/changes-in-2-4-since-2-3.adoc | 12 ++++++++++++ .../previous-whats-new/earlier-releases.adoc | 6 ------ .../message-converter-changes.adoc | 7 ------- .../previous-whats-new/stream-support-changes.adoc | 7 ------- src/reference/antora/modules/ROOT/pages/stream.adoc | 2 -- 7 files changed, 12 insertions(+), 27 deletions(-) delete mode 100644 src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/earlier-releases.adoc delete mode 100644 src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/message-converter-changes.adoc delete mode 100644 src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/stream-support-changes.adoc diff --git a/src/reference/antora/modules/ROOT/nav.adoc b/src/reference/antora/modules/ROOT/nav.adoc index a947118935..b4327b384a 100644 --- a/src/reference/antora/modules/ROOT/nav.adoc +++ b/src/reference/antora/modules/ROOT/nav.adoc @@ -71,14 +71,11 @@ *** xref:appendix/previous-whats-new/changes-in-3-1-since-3-0.adoc[] *** xref:appendix/previous-whats-new/changes-in-3-0-since-2-4.adoc[] *** xref:appendix/previous-whats-new/changes-in-2-4-since-2-3.adoc[] -*** xref:appendix/previous-whats-new/message-converter-changes.adoc[] -*** xref:appendix/previous-whats-new/stream-support-changes.adoc[] *** xref:appendix/previous-whats-new/changes-in-2-3-since-2-2.adoc[] *** xref:appendix/previous-whats-new/changes-in-2-2-since-2-1.adoc[] *** xref:appendix/previous-whats-new/changes-in-2-1-since-2-0.adoc[] *** xref:appendix/previous-whats-new/changes-in-2-0-since-1-7.adoc[] *** xref:appendix/previous-whats-new/changes-in-1-7-since-1-6.adoc[] -*** xref:appendix/previous-whats-new/earlier-releases.adoc[] *** xref:appendix/previous-whats-new/changes-in-1-6-since-1-5.adoc[] *** xref:appendix/previous-whats-new/changes-in-1-5-since-1-4.adoc[] *** xref:appendix/previous-whats-new/changes-in-1-4-since-1-3.adoc[] diff --git a/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc b/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc index 2a17bb8350..3689437cb3 100644 --- a/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc +++ b/src/reference/antora/modules/ROOT/pages/amqp/request-reply.adoc @@ -290,8 +290,6 @@ Version 2.0 introduced variants of these methods (`convertSendAndReceiveAsType`) You must configure the underlying `RabbitTemplate` with a `SmartMessageConverter`. See xref:amqp/message-converters.adoc#json-complex[Converting From a `Message` With `RabbitTemplate`] for more information. -IMPORTANT: Starting with version 3.0, the `AsyncRabbitTemplate` methods now return `CompletableFuture` s instead of `ListenableFuture` s. - [[remoting]] == Spring Remoting with AMQP diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-4-since-2-3.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-4-since-2-3.adoc index 0dc4bf3fcc..372f46fcff 100644 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-4-since-2-3.adoc +++ b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/changes-in-2-4-since-2-3.adoc @@ -22,3 +22,15 @@ See xref:amqp/broker-configuration.adoc#declarable-recovery[Recovering Auto-Dele Support remoting using Spring Framework’s RMI support is deprecated and will be removed in 3.0. See Spring Remoting with AMQP for more information. +[[stream-support-changes]] +== Stream Support Changes + +`RabbitStreamOperations` and `RabbitStreamTemplate` have been deprecated in favor of `RabbitStreamOperations2` and `RabbitStreamTemplate2` respectively; they return `CompletableFuture` instead of `ListenableFuture`. +See xref:stream.adoc[Using the RabbitMQ Stream Plugin] for more information. + +[[message-converter-changes]] +== Message Converter Changes + +The `Jackson2JsonMessageConverter` can now determine the charset from the `contentEncoding` header. +See xref:amqp/message-converters.adoc#json-message-converter[`Jackson2JsonMessageConverter`] for more information. + diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/earlier-releases.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/earlier-releases.adoc deleted file mode 100644 index d92f5b10f6..0000000000 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/earlier-releases.adoc +++ /dev/null @@ -1,6 +0,0 @@ -[[earlier-releases]] -= Earlier Releases -:page-section-summary-toc: 1 - -See xref:appendix/previous-whats-new.adoc[Previous Releases] for changes in previous versions. - diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/message-converter-changes.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/message-converter-changes.adoc deleted file mode 100644 index 693a71cf40..0000000000 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/message-converter-changes.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[message-converter-changes]] -= Message Converter Changes -:page-section-summary-toc: 1 - -The `Jackson2JsonMessageConverter` can now determine the charset from the `contentEncoding` header. -See xref:amqp/message-converters.adoc#json-message-converter[`Jackson2JsonMessageConverter`] for more information. - diff --git a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/stream-support-changes.adoc b/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/stream-support-changes.adoc deleted file mode 100644 index b6be8ec44a..0000000000 --- a/src/reference/antora/modules/ROOT/pages/appendix/previous-whats-new/stream-support-changes.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[stream-support-changes]] -= Stream Support Changes -:page-section-summary-toc: 1 - -`RabbitStreamOperations` and `RabbitStreamTemplate` have been deprecated in favor of `RabbitStreamOperations2` and `RabbitStreamTemplate2` respectively; they return `CompletableFuture` instead of `ListenableFuture`. -See xref:stream.adoc[Using the RabbitMQ Stream Plugin] for more information. - diff --git a/src/reference/antora/modules/ROOT/pages/stream.adoc b/src/reference/antora/modules/ROOT/pages/stream.adoc index e9f5119e03..b1e35babbf 100644 --- a/src/reference/antora/modules/ROOT/pages/stream.adoc +++ b/src/reference/antora/modules/ROOT/pages/stream.adoc @@ -111,8 +111,6 @@ The `ProducerCustomizer` provides a mechanism to customize the producer before i Refer to the {rabbitmq-stream-docs}[Java Client Documentation] about customizing the `Environment` and `Producer`. -IMPORTANT: Starting with version 3.0, the method return types are `CompletableFuture` instead of `ListenableFuture`. - [[receiving-messages]] == Receiving Messages From 6daa286bc0e2e3eace8dc095dd7758999a49ba56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 02:55:16 +0000 Subject: [PATCH 075/111] Bump com.fasterxml.jackson:jackson-bom from 2.18.0 to 2.18.1 (#2888) Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.0 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.0...jackson-bom-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 096b2900aa..aa5190baa0 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ ext { commonsPoolVersion = '2.12.0' hamcrestVersion = '3.0' hibernateValidationVersion = '8.0.1.Final' - jacksonBomVersion = '2.18.0' + jacksonBomVersion = '2.18.1' jaywayJsonPathVersion = '2.9.0' junit4Version = '4.13.2' junitJupiterVersion = '5.11.3' From ccca9d9b8e5d2d2c2e6afe0c71353292363b77f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 02:55:33 +0000 Subject: [PATCH 076/111] Bump the development-dependencies group with 2 updates (#2887) Bumps the development-dependencies group with 2 updates: [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) and com.github.spotbugs. Updates `org.apache.httpcomponents.client5:httpclient5` from 5.4 to 5.4.1 - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.4.1/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.4...rel/v5.4.1) Updates `com.github.spotbugs` from 6.0.25 to 6.0.26 --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: com.github.spotbugs dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index aa5190baa0..561bbbf04d 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id 'io.spring.dependency-management' version '1.1.6' apply false id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' - id 'com.github.spotbugs' version '6.0.25' + id 'com.github.spotbugs' version '6.0.26' id 'io.freefair.aggregate-javadoc' version '8.10.2' } @@ -48,7 +48,7 @@ ext { assertjVersion = '3.26.3' assertkVersion = '0.28.1' awaitilityVersion = '4.2.2' - commonsHttpClientVersion = '5.4' + commonsHttpClientVersion = '5.4.1' commonsPoolVersion = '2.12.0' hamcrestVersion = '3.0' hibernateValidationVersion = '8.0.1.Final' From 0c72649ec70afb4ac58001ee69cc3d02c44508ad Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 9 Nov 2024 05:02:14 +0700 Subject: [PATCH 077/111] Fix typos in Javadoc and variable names --- .../org/springframework/amqp/rabbit/junit/LongRunning.java | 4 ++-- .../rabbit/config/AbstractRabbitListenerContainerFactory.java | 4 ++-- .../springframework/amqp/rabbit/config/NamespaceUtils.java | 2 +- .../config/StatefulRetryOperationsInterceptorFactoryBean.java | 4 ++-- .../amqp/rabbit/connection/CompositeConnectionListener.java | 2 +- .../amqp/rabbit/connection/RabbitConnectionFactoryBean.java | 2 +- .../amqp/rabbit/listener/adapter/MessageListenerAdapter.java | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LongRunning.java b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LongRunning.java index f2e3a5d85c..9ea1221489 100644 --- a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LongRunning.java +++ b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LongRunning.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ public @interface LongRunning { /** - * The name of the variable/property used to determine whether long runnning tests + * The name of the variable/property used to determine whether long running tests * should run. * @return the name of the variable/property. */ diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractRabbitListenerContainerFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractRabbitListenerContainerFactory.java index f1ec63668a..bdbce98737 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractRabbitListenerContainerFactory.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/AbstractRabbitListenerContainerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -344,7 +344,7 @@ public void setObservationConvention(RabbitListenerObservationConvention observa /** * Set to true to stop the container after the current message(s) are processed and * requeue any prefetched. Useful when using exclusive or single-active consumers. - * @param forceStop true to stop when current messsage(s) are processed. + * @param forceStop true to stop when current message(s) are processed. * @since 2.4.15 */ public void setForceStop(boolean forceStop) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java index d7b6dbd971..5b99acef0f 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/NamespaceUtils.java @@ -126,7 +126,7 @@ public static boolean addConstructorArgValueIfAttributeDefined(BeanDefinitionBui * @param builder the bean definition builder to be configured * @param element the XML element where the attribute should be defined * @param attributeName the name of the attribute whose value will be used as a constructor argument - * @param defaultValue the default value to use if the attirbute is not set + * @param defaultValue the default value to use if the attribute is not set */ public static void addConstructorArgBooleanValueIfAttributeDefined(BeanDefinitionBuilder builder, Element element, String attributeName, boolean defaultValue) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java index 4a468f750f..4e79caaa98 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/config/StatefulRetryOperationsInterceptorFactoryBean.java @@ -63,8 +63,8 @@ public class StatefulRetryOperationsInterceptorFactoryBean extends AbstractRetry private NewMessageIdentifier newMessageIdentifier; - public void setMessageKeyGenerator(MessageKeyGenerator messageKeyGeneretor) { - this.messageKeyGenerator = messageKeyGeneretor; + public void setMessageKeyGenerator(MessageKeyGenerator messageKeyGenerator) { + this.messageKeyGenerator = messageKeyGenerator; } public void setNewMessageIdentifier(NewMessageIdentifier newMessageIdentifier) { diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java index 0c9900cd77..e8d9746446 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CompositeConnectionListener.java @@ -23,7 +23,7 @@ import com.rabbitmq.client.ShutdownSignalException; /** - * A composite listener that invokes its delegages in turn. + * A composite listener that invokes its delegates in turn. * * @author Dave Syer * @author Gary Russell diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java index 779bdef7c9..944402231e 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java @@ -63,7 +63,7 @@ * optionally enabling SSL, with or without certificate validation. When * {@link #setSslPropertiesLocation(Resource) sslPropertiesLocation} is not null, the * default implementation loads a {@code PKCS12} keystore and a {@code JKS} truststore - * using the supplied properties and intializes key and trust manager factories, using + * using the supplied properties and initializes key and trust manager factories, using * algorithm {@code SunX509} by default. These are then used to initialize an * {@link SSLContext} using the {@link #setSslAlgorithm(String) sslAlgorithm} (default * TLSv1.2, falling back to TLSv1.1, if 1.2 is not available). diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java index 65667d8453..b101a33954 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessageListenerAdapter.java @@ -89,7 +89,7 @@ * * This next example illustrates a Message delegate that just consumes the String contents of * {@link Message Messages}. Notice also how the name of the Message handling method is different from the - * {@link #ORIGINAL_DEFAULT_LISTENER_METHOD original} (this will have to be configured in the attandant bean + * {@link #ORIGINAL_DEFAULT_LISTENER_METHOD original} (this will have to be configured in the attendant bean * definition). Again, no Message will be sent back as the method returns void. * *

From a2ac767c0d0462e1b8199015f4f5de12a4d8188e Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 11 Nov 2024 12:31:35 -0500
Subject: [PATCH 078/111] GH-2890: Fix `MessagingMessageListenerAdapter` for
 batch in Kotlin

Fixes: #2890
Issue link: https://github.com/spring-projects/spring-amqp/issues/2890

The Kotlin function with signature `receiveBatch(messages: List)`
produced a `WildCardType` for the generic of the `List` argument.

* Fix `MessagingMessageListenerAdapter` to use `TypeUtils.isAssignable()`
to determine if the `Type` has a part as expected type

**Auto-cherry-pick to `3.1.x`**
---
 .../adapter/MessagingMessageListenerAdapter.java   | 14 ++++++++------
 .../rabbit/annotation/EnableRabbitKotlinTests.kt   |  9 ++++++---
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapter.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapter.java
index 47ffbed9ee..88313d0bd2 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapter.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/adapter/MessagingMessageListenerAdapter.java
@@ -41,6 +41,7 @@
 import org.springframework.messaging.handler.annotation.Headers;
 import org.springframework.messaging.handler.annotation.Payload;
 import org.springframework.util.Assert;
+import org.springframework.util.TypeUtils;
 
 import com.rabbitmq.client.Channel;
 
@@ -456,17 +457,18 @@ private Type extractGenericParameterTypFromMethodParameter(MethodParameter metho
 				if (parameterizedType.getRawType().equals(Message.class)) {
 					genericParameterType = ((ParameterizedType) genericParameterType).getActualTypeArguments()[0];
 				}
-				else if (this.isBatch
-						&& ((parameterizedType.getRawType().equals(List.class)
-						|| parameterizedType.getRawType().equals(Collection.class))
-						&& parameterizedType.getActualTypeArguments().length == 1)) {
+				else if (this.isBatch &&
+						(parameterizedType.getRawType().equals(List.class) ||
+								(parameterizedType.getRawType().equals(Collection.class) &&
+										parameterizedType.getActualTypeArguments().length == 1))) {
 
 					this.isCollection = true;
 					Type paramType = parameterizedType.getActualTypeArguments()[0];
 					boolean messageHasGeneric = paramType instanceof ParameterizedType pType
 							&& pType.getRawType().equals(Message.class);
-					this.isMessageList = paramType.equals(Message.class) || messageHasGeneric;
-					this.isAmqpMessageList = paramType.equals(org.springframework.amqp.core.Message.class);
+					this.isMessageList = TypeUtils.isAssignable(paramType, Message.class) || messageHasGeneric;
+					this.isAmqpMessageList =
+							TypeUtils.isAssignable(paramType, org.springframework.amqp.core.Message.class);
 					if (messageHasGeneric) {
 						genericParameterType = ((ParameterizedType) paramType).getActualTypeArguments()[0];
 					}
diff --git a/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt b/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt
index 4b94a657e6..8e9f452f9f 100644
--- a/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt
+++ b/spring-rabbit/src/test/kotlin/org/springframework/amqp/rabbit/annotation/EnableRabbitKotlinTests.kt
@@ -19,9 +19,11 @@ package org.springframework.amqp.rabbit.annotation
 import assertk.assertThat
 import assertk.assertions.containsOnly
 import assertk.assertions.isEqualTo
+import assertk.assertions.isInstanceOf
 import assertk.assertions.isTrue
 import org.junit.jupiter.api.Test
 import org.springframework.amqp.core.AcknowledgeMode
+import org.springframework.amqp.core.Message
 import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
 import org.springframework.amqp.rabbit.connection.CachingConnectionFactory
 import org.springframework.amqp.rabbit.core.RabbitTemplate
@@ -77,7 +79,8 @@ class EnableRabbitKotlinTests {
 		template.convertAndSend("kotlinBatchQueue", "test1")
 		template.convertAndSend("kotlinBatchQueue", "test2")
 		assertThat(this.config.batchReceived.await(10, TimeUnit.SECONDS)).isTrue()
-		assertThat(this.config.batch).containsOnly("test1", "test2")
+		assertThat(this.config.batch[0]).isInstanceOf(Message::class.java)
+		assertThat(this.config.batch.map { m -> String(m.body) }).containsOnly("test1", "test2")
 	}
 
 	@Test
@@ -100,11 +103,11 @@ class EnableRabbitKotlinTests {
 
 		val batchReceived = CountDownLatch(1)
 
-		lateinit var batch: List
+		lateinit var batch: List
 
 		@RabbitListener(id = "batch", queues = ["kotlinBatchQueue"],
 				containerFactory = "batchRabbitListenerContainerFactory")
-		suspend fun receiveBatch(messages: List) {
+		suspend fun receiveBatch(messages: List) {
 			batch = messages
 			batchReceived.countDown()
 		}

From 547167960b9fa30fc50f7e0f9b74a880e69a739e Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 11 Nov 2024 18:15:42 -0500
Subject: [PATCH 079/111] GH-2891: Add
 `rabbitConnection.addShutdownListener(this)`

Fixes: #2891
Issue link: https://github.com/spring-projects/spring-amqp/issues/2891

The `ShutdownListener` is not registered into connections created by the `AbstractConnectionFactory`

* Fix `AbstractConnectionFactory.createBareConnection()` add itself into just created connection as a `ShutdownListener`
* Fix tests with mocks where `mockConnectionFactory.newConnection()` did not return an instance of `Connection`
---
 .../connection/AbstractConnectionFactory.java | 15 ++---
 .../AbstractConnectionFactoryTests.java       | 24 ++++----
 .../CachingConnectionFactoryTests.java        | 58 +++++++++++--------
 .../core/RabbitAdminDeclarationTests.java     | 45 --------------
 4 files changed, 48 insertions(+), 94 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
index 33cb11dccf..97ef229871 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
@@ -166,6 +166,7 @@ public void handleRecovery(Recoverable recoverable) {
 
 	@Nullable
 	private BackOff connectionCreatingBackOff;
+
 	/**
 	 * Create a new AbstractConnectionFactory for the given target ConnectionFactory, with no publisher connection
 	 * factory.
@@ -580,8 +581,8 @@ public ConnectionFactory getPublisherConnectionFactory() {
 	protected final Connection createBareConnection() {
 		try {
 			String connectionName = this.connectionNameStrategy.obtainNewConnectionName(this);
-
 			com.rabbitmq.client.Connection rabbitConnection = connect(connectionName);
+			rabbitConnection.addShutdownListener(this);
 			Connection connection = new SimpleConnection(rabbitConnection, this.closeTimeout,
 					this.connectionCreatingBackOff == null ? null : this.connectionCreatingBackOff.start());
 			if (rabbitConnection instanceof AutorecoveringConnection auto) {
@@ -732,16 +733,8 @@ public String toString() {
 		}
 	}
 
-	private static final class ConnectionBlockedListener implements BlockedListener {
-
-		private final Connection connection;
-
-		private final ApplicationEventPublisher applicationEventPublisher;
-
-		ConnectionBlockedListener(Connection connection, ApplicationEventPublisher applicationEventPublisher) {
-			this.connection = connection;
-			this.applicationEventPublisher = applicationEventPublisher;
-		}
+	private record ConnectionBlockedListener(Connection connection, ApplicationEventPublisher applicationEventPublisher)
+			implements BlockedListener {
 
 		@Override
 		public void handleBlocked(String reason) {
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
index 58546447c8..e41ea8635d 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
@@ -20,6 +20,7 @@
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.BDDMockito.willCallRealMethod;
@@ -64,11 +65,11 @@ public abstract class AbstractConnectionFactoryTests {
 
 	@Test
 	public void testWithListener() throws Exception {
-
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-		com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
+		com.rabbitmq.client.Connection mockConnection = mock();
 
 		given(mockConnectionFactory.newConnection(any(ExecutorService.class), anyString())).willReturn(mockConnection);
+		given(mockConnectionFactory.newConnection(any(), anyList(), anyString())).willReturn(mockConnection);
 
 		final AtomicInteger called = new AtomicInteger(0);
 		AbstractConnectionFactory connectionFactory = createConnectionFactory(mockConnectionFactory);
@@ -125,9 +126,8 @@ public void onClose(Connection connection) {
 
 	@Test
 	public void testWithListenerRegisteredAfterOpen() throws Exception {
-
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-		com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
+		com.rabbitmq.client.Connection mockConnection = mock();
 
 		given(mockConnectionFactory.newConnection(any(ExecutorService.class), anyString())).willReturn(mockConnection);
 
@@ -168,10 +168,9 @@ public void onClose(Connection connection) {
 
 	@Test
 	public void testCloseInvalidConnection() throws Exception {
-
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-		com.rabbitmq.client.Connection mockConnection1 = mock(com.rabbitmq.client.Connection.class);
-		com.rabbitmq.client.Connection mockConnection2 = mock(com.rabbitmq.client.Connection.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
+		com.rabbitmq.client.Connection mockConnection1 = mock();
+		com.rabbitmq.client.Connection mockConnection2 = mock();
 
 		given(mockConnectionFactory.newConnection(any(ExecutorService.class), anyString()))
 				.willReturn(mockConnection1, mockConnection2);
@@ -194,8 +193,7 @@ public void testCloseInvalidConnection() throws Exception {
 
 	@Test
 	public void testDestroyBeforeUsed() throws Exception {
-
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
 
 		AbstractConnectionFactory connectionFactory = createConnectionFactory(mockConnectionFactory);
 		connectionFactory.destroy();
@@ -205,7 +203,7 @@ public void testDestroyBeforeUsed() throws Exception {
 
 	@Test
 	public void testCreatesConnectionWithGivenFactory() {
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
 		willCallRealMethod().given(mockConnectionFactory).params(any(ExecutorService.class));
 		willCallRealMethod().given(mockConnectionFactory).setThreadFactory(any(ThreadFactory.class));
 		willCallRealMethod().given(mockConnectionFactory).getThreadFactory();
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactoryTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactoryTests.java
index 66dc8013ec..8ecddfcb40 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactoryTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactoryTests.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -117,7 +118,7 @@ void stringRepresentation() {
 		assertThat(ccf.toString()).contains(", addresses=[h3:1236, h4:1237]")
 				.doesNotContain("host")
 				.doesNotContain("port");
-		ccf.setAddressResolver(() ->  {
+		ccf.setAddressResolver(() -> {
 			throw new IOException("test");
 		});
 		ccf.setPort(0);
@@ -710,7 +711,7 @@ public void testCheckoutLimitWithPublisherConfirmsLogicalAlreadyCloses() throws
 		willAnswer(invoc -> {
 			open.set(false); // so the logical close detects a closed delegate
 			return null;
-		}).given(mockChannel).basicPublish(any(), any(), anyBoolean(),  any(), any());
+		}).given(mockChannel).basicPublish(any(), any(), anyBoolean(), any(), any());
 
 		CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory);
 		ccf.setExecutor(mock(ExecutorService.class));
@@ -722,7 +723,7 @@ public void testCheckoutLimitWithPublisherConfirmsLogicalAlreadyCloses() throws
 		rabbitTemplate.convertAndSend("foo", "bar");
 		open.set(true);
 		rabbitTemplate.convertAndSend("foo", "bar");
-		verify(mockChannel, times(2)).basicPublish(any(), any(), anyBoolean(),  any(), any());
+		verify(mockChannel, times(2)).basicPublish(any(), any(), anyBoolean(), any(), any());
 	}
 
 	@Test
@@ -1300,7 +1301,6 @@ public void onClose(Connection connection) {
 		verify(mockConnections.get(3)).close(30000);
 	}
 
-
 	@Test
 	public void testWithConnectionFactoryCachedConnectionAndChannels() throws Exception {
 		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
@@ -1644,6 +1644,8 @@ private void verifyChannelIs(Channel mockChannel, Channel channel) {
 	@Test
 	public void setAddressesEmpty() throws Exception {
 		ConnectionFactory mock = mock(com.rabbitmq.client.ConnectionFactory.class);
+		given(mock.newConnection(any(ExecutorService.class), anyString()))
+				.willReturn(mock(com.rabbitmq.client.Connection.class));
 		CachingConnectionFactory ccf = new CachingConnectionFactory(mock);
 		ccf.setExecutor(mock(ExecutorService.class));
 		ccf.setHost("abc");
@@ -1663,6 +1665,8 @@ public void setAddressesEmpty() throws Exception {
 	@Test
 	public void setAddressesOneHost() throws Exception {
 		ConnectionFactory mock = mock(com.rabbitmq.client.ConnectionFactory.class);
+		given(mock.newConnection(any(), anyList(), anyString()))
+				.willReturn(mock(com.rabbitmq.client.Connection.class));
 		CachingConnectionFactory ccf = new CachingConnectionFactory(mock);
 		ccf.setAddresses("mq1");
 		ccf.createConnection();
@@ -1674,8 +1678,9 @@ public void setAddressesOneHost() throws Exception {
 
 	@Test
 	public void setAddressesTwoHosts() throws Exception {
-		ConnectionFactory mock = mock(com.rabbitmq.client.ConnectionFactory.class);
+		ConnectionFactory mock = mock();
 		willReturn(true).given(mock).isAutomaticRecoveryEnabled();
+		willReturn(mock(com.rabbitmq.client.Connection.class)).given(mock).newConnection(any(), anyList(), anyString());
 		CachingConnectionFactory ccf = new CachingConnectionFactory(mock);
 		ccf.setAddresses("mq1,mq2");
 		ccf.createConnection();
@@ -1683,7 +1688,8 @@ public void setAddressesTwoHosts() throws Exception {
 		verify(mock).setAutomaticRecoveryEnabled(false);
 		verify(mock).newConnection(
 				isNull(),
-				argThat((ArgumentMatcher>) a -> a.size() == 2 && a.contains(new Address("mq1")) && a.contains(new Address("mq2"))),
+				argThat((ArgumentMatcher>) a -> a.size() == 2
+						&& a.contains(new Address("mq1")) && a.contains(new Address("mq2"))),
 				anyString());
 		verifyNoMoreInteractions(mock);
 	}
@@ -1692,7 +1698,9 @@ public void setAddressesTwoHosts() throws Exception {
 	public void setUri() throws Exception {
 		URI uri = new URI("amqp://localhost:1234/%2f");
 
-		ConnectionFactory mock = mock(com.rabbitmq.client.ConnectionFactory.class);
+		ConnectionFactory mock = mock();
+		given(mock.newConnection(any(ExecutorService.class), anyString()))
+				.willReturn(mock(com.rabbitmq.client.Connection.class));
 		CachingConnectionFactory ccf = new CachingConnectionFactory(mock);
 		ccf.setExecutor(mock(ExecutorService.class));
 
@@ -1854,12 +1862,12 @@ public void testFirstConnectionDoesntWait() throws IOException, TimeoutException
 	@SuppressWarnings("unchecked")
 	@Test
 	public void testShuffleRandom() throws IOException, TimeoutException {
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-		com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
+		com.rabbitmq.client.Connection mockConnection = mock();
 		Channel mockChannel = mock(Channel.class);
 
-		given(mockConnectionFactory.newConnection((ExecutorService) isNull(), any(List.class), anyString()))
-			.willReturn(mockConnection);
+		given(mockConnectionFactory.newConnection(any(), anyList(), anyString()))
+				.willReturn(mockConnection);
 		given(mockConnection.createChannel()).willReturn(mockChannel);
 		given(mockChannel.isOpen()).willReturn(true);
 		given(mockConnection.isOpen()).willReturn(true);
@@ -1873,11 +1881,11 @@ public void testShuffleRandom() throws IOException, TimeoutException {
 		ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
 		verify(mockConnectionFactory, times(100)).newConnection(isNull(), captor.capture(), anyString());
 		List firstAddress = captor.getAllValues()
-			.stream()
-			.map(addresses -> addresses.get(0).getHost())
-			.distinct()
-			.sorted()
-			.collect(Collectors.toList());
+				.stream()
+				.map(addresses -> addresses.get(0).getHost())
+				.distinct()
+				.sorted()
+				.collect(Collectors.toList());
 		assertThat(firstAddress).containsExactly("host1", "host2", "host3");
 	}
 
@@ -1888,8 +1896,8 @@ public void testShuffleInOrder() throws IOException, TimeoutException {
 		com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class);
 		Channel mockChannel = mock(Channel.class);
 
-		given(mockConnectionFactory.newConnection((ExecutorService) isNull(), any(List.class), anyString()))
-			.willReturn(mockConnection);
+		given(mockConnectionFactory.newConnection(isNull(), anyList(), anyString()))
+				.willReturn(mockConnection);
 		given(mockConnection.createChannel()).willReturn(mockChannel);
 		given(mockChannel.isOpen()).willReturn(true);
 		given(mockConnection.isOpen()).willReturn(true);
@@ -1903,17 +1911,17 @@ public void testShuffleInOrder() throws IOException, TimeoutException {
 		ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
 		verify(mockConnectionFactory, times(3)).newConnection(isNull(), captor.capture(), anyString());
 		List connectAddresses = captor.getAllValues()
-			.stream()
-			.map(addresses -> addresses.get(0).getHost())
-			.collect(Collectors.toList());
+				.stream()
+				.map(addresses -> addresses.get(0).getHost())
+				.collect(Collectors.toList());
 		assertThat(connectAddresses).containsExactly("host1", "host2", "host3");
 	}
 
 	@Test
 	void testResolver() throws Exception {
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-		com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class);
-		Channel mockChannel = mock(Channel.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
+		com.rabbitmq.client.Connection mockConnection = mock();
+		Channel mockChannel = mock();
 
 		AddressResolver resolver = () -> Collections.singletonList(Address.parseAddress("foo:5672"));
 		given(mockConnectionFactory.newConnection(any(ExecutorService.class), eq(resolver), anyString()))
@@ -1934,7 +1942,7 @@ void testResolver() throws Exception {
 
 	@Test
 	void nullShutdownCause() {
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
+		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock();
 		AbstractConnectionFactory cf = createConnectionFactory(mockConnectionFactory);
 		AtomicBoolean connShutDown = new AtomicBoolean();
 		cf.addConnectionListener(new ConnectionListener() {
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java
index fe9b092554..a6d04075b3 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminDeclarationTests.java
@@ -32,12 +32,9 @@
 import static org.mockito.Mockito.verify;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.junit.jupiter.api.Test;
@@ -50,7 +47,6 @@
 import org.springframework.amqp.core.Exchange;
 import org.springframework.amqp.core.Queue;
 import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
-import org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CacheMode;
 import org.springframework.amqp.rabbit.connection.Connection;
 import org.springframework.amqp.rabbit.connection.ConnectionFactory;
 import org.springframework.amqp.rabbit.connection.ConnectionListener;
@@ -104,47 +100,6 @@ public void testUnconditional() throws Exception {
 		verify(channel).queueBind("foo", "bar", "foo", new HashMap<>());
 	}
 
-	@Test
-	public void testNoDeclareWithCachedConnections() throws Exception {
-		com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
-
-		List mockChannels = new ArrayList<>();
-
-		AtomicInteger connectionNumber = new AtomicInteger();
-		willAnswer(invocation -> {
-			com.rabbitmq.client.Connection connection = mock(com.rabbitmq.client.Connection.class);
-			AtomicInteger channelNumber = new AtomicInteger();
-			willAnswer(invocation1 -> {
-				Channel channel = mock(Channel.class);
-				given(channel.isOpen()).willReturn(true);
-				int channelNum = channelNumber.incrementAndGet();
-				given(channel.toString()).willReturn("mockChannel" + channelNum);
-				mockChannels.add(channel);
-				return channel;
-			}).given(connection).createChannel();
-			int connectionNum = connectionNumber.incrementAndGet();
-			given(connection.toString()).willReturn("mockConnection" + connectionNum);
-			given(connection.isOpen()).willReturn(true);
-			return connection;
-		}).given(mockConnectionFactory).newConnection((ExecutorService) null);
-
-		CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory);
-		ccf.setCacheMode(CacheMode.CONNECTION);
-		ccf.afterPropertiesSet();
-
-		RabbitAdmin admin = new RabbitAdmin(ccf);
-		GenericApplicationContext context = new GenericApplicationContext();
-		Queue queue = new Queue("foo");
-		context.getBeanFactory().registerSingleton("foo", queue);
-		context.refresh();
-		admin.setApplicationContext(context);
-		admin.afterPropertiesSet();
-		ccf.createConnection().close();
-		ccf.destroy();
-
-		assertThat(mockChannels.size()).as("Admin should not have created a channel").isEqualTo(0);
-	}
-
 	@Test
 	public void testUnconditionalWithExplicitFactory() throws Exception {
 		ConnectionFactory cf = mock(ConnectionFactory.class);

From f112115ead608ca4d9a7aceb6d3d9fa536704ede Mon Sep 17 00:00:00 2001
From: Alex Dumitrescu <6016800+axldev@users.noreply.github.com>
Date: Tue, 12 Nov 2024 16:16:19 +0100
Subject: [PATCH 080/111] Fix typos in Javadoc

---
 .../amqp/support/converter/MessageConversionException.java      | 2 +-
 .../springframework/amqp/rabbit/annotation/EnableRabbit.java    | 2 +-
 .../amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessageConversionException.java b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessageConversionException.java
index 376a3c2429..c2e879394d 100644
--- a/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessageConversionException.java
+++ b/spring-amqp/src/main/java/org/springframework/amqp/support/converter/MessageConversionException.java
@@ -23,7 +23,7 @@
  * Exception to be thrown by message converters if they encounter a problem with converting a message or object.
  * 

*

- * N.B. this is not an {@link AmqpException} because it is a a client exception, not a protocol or broker + * N.B. this is not an {@link AmqpException} because it is a client exception, not a protocol or broker * problem. *

* diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/EnableRabbit.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/EnableRabbit.java index b22cc737d9..a83d043419 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/EnableRabbit.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/EnableRabbit.java @@ -104,7 +104,7 @@ *

Annotated methods can use flexible signature; in particular, it is possible to use * the {@link org.springframework.messaging.Message Message} abstraction and related annotations, * see {@link RabbitListener} Javadoc for more details. For instance, the following would - * inject the content of the message and a a custom "myCounter" AMQP header: + * inject the content of the message and a custom "myCounter" AMQP header: * *

  * @RabbitListener(containerFactory = "myRabbitListenerContainerFactory", queues = "myQueue")
diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java
index de0a38f538..95bcaffc40 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/listener/AbstractRabbitListenerEndpoint.java
@@ -426,7 +426,7 @@ public void setupListenerContainer(MessageListenerContainer listenerContainer) {
 	 * Create a {@link MessageListener} that is able to serve this endpoint for the
 	 * specified container.
 	 * @param container the {@link MessageListenerContainer} to create a {@link MessageListener}.
-	 * @return a a {@link MessageListener} instance.
+	 * @return a {@link MessageListener} instance.
 	 */
 	protected abstract MessageListener createMessageListener(MessageListenerContainer container);
 

From 9eb857c1cd693880aced2d0f2fe8415d4f3680b0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 16 Nov 2024 02:15:28 +0000
Subject: [PATCH 081/111] Bump io.micrometer:micrometer-bom (#2901)

Bumps [io.micrometer:micrometer-bom](https://github.com/micrometer-metrics/micrometer) from 1.14.0-SNAPSHOT to 1.14.2-SNAPSHOT.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/commits)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 561bbbf04d..413062e569 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,7 +60,7 @@ ext {
 	log4jVersion = '2.24.1'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
-	micrometerVersion = '1.14.0-SNAPSHOT'
+	micrometerVersion = '1.14.2-SNAPSHOT'
 	micrometerTracingVersion = '1.4.0-SNAPSHOT'
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'

From 282fef8ae220ac36aeba17543ff18c2128276376 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 16 Nov 2024 02:15:58 +0000
Subject: [PATCH 082/111] Bump io.projectreactor:reactor-bom (#2897)

Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2024.0.0-SNAPSHOT to 2024.0.1-SNAPSHOT.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/commits)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 413062e569..dd8935fec3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -65,7 +65,7 @@ ext {
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'
-	reactorVersion = '2024.0.0-SNAPSHOT'
+	reactorVersion = '2024.0.1-SNAPSHOT'
 	springDataVersion = '2024.1.0-SNAPSHOT'
 	springRetryVersion = '2.0.10'
 	springVersion = '6.2.0-SNAPSHOT'

From 287a5f9d04bf27860309f946fc5fa210e749d5c4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 16 Nov 2024 02:16:09 +0000
Subject: [PATCH 083/111] Bump org.springframework:spring-framework-bom (#2899)

Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.0-SNAPSHOT to 6.2.1-SNAPSHOT.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/commits)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index dd8935fec3..caf4f204bc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -68,7 +68,7 @@ ext {
 	reactorVersion = '2024.0.1-SNAPSHOT'
 	springDataVersion = '2024.1.0-SNAPSHOT'
 	springRetryVersion = '2.0.10'
-	springVersion = '6.2.0-SNAPSHOT'
+	springVersion = '6.2.1-SNAPSHOT'
 	testcontainersVersion = '1.20.3'
 
 	javaProjects = subprojects - project(':spring-amqp-bom')

From ac875c893b7882b52f9ab86ef612ed14f8f55f46 Mon Sep 17 00:00:00 2001
From: Tran Ngoc Nhan 
Date: Mon, 18 Nov 2024 21:52:02 +0700
Subject: [PATCH 084/111] Fix typo in reference document

---
 .../antora/modules/ROOT/pages/amqp/containerAttributes.adoc     | 2 +-
 .../async-annotation-driven/error-handling.adoc                 | 2 +-
 src/reference/antora/modules/ROOT/pages/amqp/template.adoc      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc b/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc
index f876898405..f3172bf9fe 100644
--- a/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc
+++ b/src/reference/antora/modules/ROOT/pages/amqp/containerAttributes.adoc
@@ -435,7 +435,7 @@ a|
 (mismatched-queues-fatal)
 
 a|When the container starts, if this property is `true` (default: `false`), the container checks that all queues declared in the context are compatible with queues already on the broker.
-If mismatched properties (such as `auto-delete`) or arguments (skuch as `x-message-ttl`) exist, the container (and application context) fails to start with a fatal exception.
+If mismatched properties (such as `auto-delete`) or arguments (such as `x-message-ttl`) exist, the container (and application context) fails to start with a fatal exception.
 
 If the problem is detected during recovery (for example, after a lost connection), the container is stopped.
 
diff --git a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/error-handling.adoc b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/error-handling.adoc
index 9c26c69de0..fe273d6adf 100644
--- a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/error-handling.adoc
+++ b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/error-handling.adoc
@@ -36,7 +36,7 @@ If you use JSON, consider using an `errorHandler` to return some other Jackson-f
 
 IMPORTANT: In version 2.1, this interface moved from package `o.s.amqp.rabbit.listener` to `o.s.amqp.rabbit.listener.api`.
 
-Starting with version 2.1.7, the `Channel` is available in a messaging message header; this allows you to ack or nack the failed messasge when using `AcknowledgeMode.MANUAL`:
+Starting with version 2.1.7, the `Channel` is available in a messaging message header; this allows you to ack or nack the failed message when using `AcknowledgeMode.MANUAL`:
 
 [source, java]
 ----
diff --git a/src/reference/antora/modules/ROOT/pages/amqp/template.adoc b/src/reference/antora/modules/ROOT/pages/amqp/template.adoc
index 55b17e8cb3..0dea17c5d3 100644
--- a/src/reference/antora/modules/ROOT/pages/amqp/template.adoc
+++ b/src/reference/antora/modules/ROOT/pages/amqp/template.adoc
@@ -195,7 +195,7 @@ In general, this means that only one confirm is outstanding on a channel at a ti
 NOTE: Starting with version 2.2, the callbacks are invoked on one of the connection factory's `executor` threads.
 This is to avoid a potential deadlock if you perform Rabbit operations from within the callback.
 With previous versions, the callbacks were invoked directly on the `amqp-client` connection I/O thread; this would deadlock if you perform some RPC operation (such as opening a new channel) since the I/O thread blocks waiting for the result, but the result needs to be processed by the I/O thread itself.
-With those versions, it was necessary to hand off work (such as sending a messasge) to another thread within the callback.
+With those versions, it was necessary to hand off work (such as sending a message) to another thread within the callback.
 This is no longer necessary since the framework now hands off the callback invocation to the executor.
 
 IMPORTANT: The guarantee of receiving a returned message before the ack is still maintained as long as the return callback executes in 60 seconds or less.

From 03258365869583dd4f15d63ba125bd4b98dc880b Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 18 Nov 2024 12:41:38 -0500
Subject: [PATCH 085/111] Revert commits for Dependabot updates to SNAPSHOTs

Essentially, Dependabot must update to the latest GA, but not SNAPSHOT

Revert "Bump org.springframework:spring-framework-bom (#2899)"

This reverts commit 287a5f9d04bf27860309f946fc5fa210e749d5c4.

Revert "Bump io.projectreactor:reactor-bom (#2897)"

This reverts commit 282fef8ae220ac36aeba17543ff18c2128276376.

Revert "Bump io.micrometer:micrometer-bom (#2901)"

This reverts commit 9eb857c1cd693880aced2d0f2fe8415d4f3680b0.
---
 build.gradle | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/build.gradle b/build.gradle
index caf4f204bc..561bbbf04d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,15 +60,15 @@ ext {
 	log4jVersion = '2.24.1'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
-	micrometerVersion = '1.14.2-SNAPSHOT'
+	micrometerVersion = '1.14.0-SNAPSHOT'
 	micrometerTracingVersion = '1.4.0-SNAPSHOT'
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'
-	reactorVersion = '2024.0.1-SNAPSHOT'
+	reactorVersion = '2024.0.0-SNAPSHOT'
 	springDataVersion = '2024.1.0-SNAPSHOT'
 	springRetryVersion = '2.0.10'
-	springVersion = '6.2.1-SNAPSHOT'
+	springVersion = '6.2.0-SNAPSHOT'
 	testcontainersVersion = '1.20.3'
 
 	javaProjects = subprojects - project(':spring-amqp-bom')

From d910a8b2bf62bc5212ca93636a85d95ac041c28f Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 18 Nov 2024 12:50:56 -0500
Subject: [PATCH 086/111] Upgrade Spring deps to GAs; prepare for release

---
 build.gradle | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/build.gradle b/build.gradle
index 561bbbf04d..f167ef1ac5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,15 +60,15 @@ ext {
 	log4jVersion = '2.24.1'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
-	micrometerVersion = '1.14.0-SNAPSHOT'
-	micrometerTracingVersion = '1.4.0-SNAPSHOT'
+	micrometerVersion = '1.14.1'
+	micrometerTracingVersion = '1.4.0'
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'
-	reactorVersion = '2024.0.0-SNAPSHOT'
-	springDataVersion = '2024.1.0-SNAPSHOT'
+	reactorVersion = '2024.0.0'
+	springDataVersion = '2024.1.0'
 	springRetryVersion = '2.0.10'
-	springVersion = '6.2.0-SNAPSHOT'
+	springVersion = '6.2.0'
 	testcontainersVersion = '1.20.3'
 
 	javaProjects = subprojects - project(':spring-amqp-bom')

From 562bc772c436e6b09527084f238b46588ba8ba6d Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 18 Nov 2024 14:49:30 -0500
Subject: [PATCH 087/111] GH-2907: Use `CF.closeTimeout` for confirms wait

Fixes: #2907

Issue link: https://github.com/spring-projects/spring-amqp/issues/2907

The current hard-coded `5 seconds` is not enough in real applications under heavy load

* Fix `CachingConnectionFactory` to use `getCloseTimeout()` for `publisherCallbackChannel.waitForConfirms()`
which is `30 seconds` by default, but can be modified via `CachingConnectionFactory.setCloseTimeout()`

**Auto-cherry-pick to `3.1.x`**
---
 .../amqp/rabbit/connection/AbstractConnectionFactory.java | 5 +++--
 .../amqp/rabbit/connection/CachingConnectionFactory.java  | 8 +++-----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
index 97ef229871..caa57d6c92 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
@@ -479,8 +479,9 @@ protected ExecutorService getExecutorService() {
 	}
 
 	/**
-	 * How long to wait (milliseconds) for a response to a connection close operation from the broker; default 30000 (30
-	 * seconds).
+	 * How long to wait (milliseconds) for a response to a connection close operation from the broker;
+	 * default 30000 (30 seconds).
+	 * Also used for {@link com.rabbitmq.client.Channel#waitForConfirms()}.
 	 * @param closeTimeout the closeTimeout to set.
 	 */
 	public void setCloseTimeout(int closeTimeout) {
diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
index f14aa989b9..0aade48321 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
@@ -1087,8 +1087,6 @@ public String toString() {
 
 	private final class CachedChannelInvocationHandler implements InvocationHandler {
 
-		private static final int ASYNC_CLOSE_TIMEOUT = 5_000;
-
 		private final ChannelCachingConnectionProxy theConnection;
 
 		private final Deque channelList;
@@ -1302,7 +1300,7 @@ private void returnToCache(ChannelProxy proxy) {
 					getChannelsExecutor()
 							.execute(() -> {
 								try {
-									publisherCallbackChannel.waitForConfirms(ASYNC_CLOSE_TIMEOUT);
+									publisherCallbackChannel.waitForConfirms(getCloseTimeout());
 								}
 								catch (InterruptedException ex) {
 									Thread.currentThread().interrupt();
@@ -1426,10 +1424,10 @@ private void asyncClose() {
 				executorService.execute(() -> {
 					try {
 						if (ConfirmType.CORRELATED.equals(CachingConnectionFactory.this.confirmType)) {
-							channel.waitForConfirmsOrDie(ASYNC_CLOSE_TIMEOUT);
+							channel.waitForConfirmsOrDie(getCloseTimeout());
 						}
 						else {
-							Thread.sleep(ASYNC_CLOSE_TIMEOUT);
+							Thread.sleep(5_000); // NOSONAR - some time to give the channel a chance to ack
 						}
 					}
 					catch (@SuppressWarnings(UNUSED) InterruptedException e1) {

From da7da60f40c55056c20487a3b59d6f70e4ea13e4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 18 Nov 2024 20:59:27 +0000
Subject: [PATCH 088/111] Bump spring-io/spring-github-workflows (#2910)

Bumps the development-dependencies group with 1 update: [spring-io/spring-github-workflows](https://github.com/spring-io/spring-github-workflows).


Updates `spring-io/spring-github-workflows` from 4 to 5
- [Release notes](https://github.com/spring-io/spring-github-workflows/releases)
- [Commits](https://github.com/spring-io/spring-github-workflows/compare/v4...v5)

---
updated-dependencies:
- dependency-name: spring-io/spring-github-workflows
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 .github/workflows/announce-milestone-planning.yml | 2 +-
 .github/workflows/auto-cherry-pick.yml            | 2 +-
 .github/workflows/backport-issue.yml              | 2 +-
 .github/workflows/deploy-docs.yml                 | 2 +-
 .github/workflows/merge-dependabot-pr.yml         | 2 +-
 .github/workflows/pr-build.yml                    | 2 +-
 .github/workflows/release.yml                     | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/announce-milestone-planning.yml b/.github/workflows/announce-milestone-planning.yml
index 1075304cd1..58ba601906 100644
--- a/.github/workflows/announce-milestone-planning.yml
+++ b/.github/workflows/announce-milestone-planning.yml
@@ -6,6 +6,6 @@ on:
 
 jobs:
   announce-milestone-planning:
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-announce-milestone-planning.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-announce-milestone-planning.yml@v5
     secrets:
       SPRING_RELEASE_CHAT_WEBHOOK_URL: ${{ secrets.SPRING_RELEASE_GCHAT_WEBHOOK_URL }}
\ No newline at end of file
diff --git a/.github/workflows/auto-cherry-pick.yml b/.github/workflows/auto-cherry-pick.yml
index bb476cb186..6ba14dde29 100644
--- a/.github/workflows/auto-cherry-pick.yml
+++ b/.github/workflows/auto-cherry-pick.yml
@@ -8,6 +8,6 @@ on:
 
 jobs:
   cherry-pick-commit:
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-cherry-pick.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-cherry-pick.yml@v5
     secrets:
       GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/backport-issue.yml b/.github/workflows/backport-issue.yml
index b329f47c85..71e42771d5 100644
--- a/.github/workflows/backport-issue.yml
+++ b/.github/workflows/backport-issue.yml
@@ -7,6 +7,6 @@ on:
 
 jobs:
   backport-issue:
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-backport-issue.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-backport-issue.yml@v5
     secrets:
       GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
index 20e3d9067f..2065ee7187 100644
--- a/.github/workflows/deploy-docs.yml
+++ b/.github/workflows/deploy-docs.yml
@@ -16,4 +16,4 @@ permissions:
 jobs:
   dispatch-docs-build:
     if: github.repository_owner == 'spring-projects'
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-dispatch-docs-build.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-dispatch-docs-build.yml@v5
diff --git a/.github/workflows/merge-dependabot-pr.yml b/.github/workflows/merge-dependabot-pr.yml
index 44a74e507b..f513c72567 100644
--- a/.github/workflows/merge-dependabot-pr.yml
+++ b/.github/workflows/merge-dependabot-pr.yml
@@ -12,7 +12,7 @@ jobs:
   merge-dependabot-pr:
     permissions: write-all
 
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@v5
     with:
       mergeArguments: --auto --squash
       autoMergeSnapshots: true
\ No newline at end of file
diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml
index 7f728da35c..c9f71e8bdf 100644
--- a/.github/workflows/pr-build.yml
+++ b/.github/workflows/pr-build.yml
@@ -8,4 +8,4 @@ on:
 
 jobs:
   build-pull-request:
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@v5
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 40dfecca8b..be8a9e40c6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,7 +12,7 @@ jobs:
       contents: write
       issues: write
 
-    uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@v4
+    uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@v5
     secrets:
       GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
       DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}

From 363be061d9f2ea16c7fe1904067c6c18d94979ff Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Mon, 18 Nov 2024 16:45:57 -0500
Subject: [PATCH 089/111] Remove `3.1.x` branch from Dependabot updates

The version `3.1.8` is the last OSS version - no updates from now on

* Also remove dependencies which we don't manage anymore
---
 .github/dependabot.yml | 49 ------------------------------------------
 1 file changed, 49 deletions(-)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 5a8f11e0aa..3db6fde556 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -28,57 +28,8 @@ updates:
          - org.hibernate.validator:hibernate-validator
          - org.apache.httpcomponents.client5:httpclient5
          - org.awaitility:awaitility
-         - org.xerial.snappy:snappy-java
-         - org.lz4:lz4-java
-         - com.github.luben:zstd-jni
-
-  - package-ecosystem: gradle
-    target-branch: 3.1.x
-    directory: /
-    schedule:
-      interval: weekly
-      day: saturday
-    ignore:
-      - dependency-name: '*'
-        update-types:
-          - version-update:semver-major
-          - version-update:semver-minor
-    open-pull-requests-limit: 10
-    labels:
-      - 'type: dependency-upgrade'
-    groups:
-      development-dependencies:
-        update-types:
-          - patch
-        patterns:
-          - com.gradle.*
-          - com.github.spotbugs
-          - io.spring.*
-          - org.ajoberstar.grgit
-          - org.antora
-          - io.micrometer:micrometer-docs-generator
-          - com.willowtreeapps.assertk:assertk-jvm
-          - org.hibernate.validator:hibernate-validator
-          - org.apache.httpcomponents.client5:httpclient5
-          - org.awaitility:awaitility
-          - org.xerial.snappy:snappy-java
-          - org.lz4:lz4-java
-          - com.github.luben:zstd-jni
-
-  - package-ecosystem: github-actions
-    directory: /
-    schedule:
-      interval: weekly
-      day: saturday
-    labels:
-      - 'type: task'
-    groups:
-      development-dependencies:
-        patterns:
-          - '*'
 
   - package-ecosystem: github-actions
-    target-branch: 3.1.x
     directory: /
     schedule:
       interval: weekly

From 1661ee91560f4b6b9ce0a60ea424a3eca4c580a1 Mon Sep 17 00:00:00 2001
From: Spring Builds 
Date: Mon, 18 Nov 2024 22:07:05 +0000
Subject: [PATCH 090/111] [artifactory-release] Release version 3.2.0

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 6bc0422ab1..18e7cac5e2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-version=3.2.0-SNAPSHOT
+version=3.2.0
 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8
 org.gradle.daemon=true
 org.gradle.caching=true

From 62fd4beaf5015afaa69d6856a1657cf52db40b1b Mon Sep 17 00:00:00 2001
From: Spring Builds 
Date: Mon, 18 Nov 2024 22:07:05 +0000
Subject: [PATCH 091/111] [artifactory-release] Next development version

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 18e7cac5e2..2b07979582 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-version=3.2.0
+version=3.2.1-SNAPSHOT
 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8
 org.gradle.daemon=true
 org.gradle.caching=true

From 0d31fa5f8395971aa70d660ab510bce0688a7ea7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2024 22:37:54 -0500
Subject: [PATCH 092/111] Bump org.testcontainers:testcontainers-bom from
 1.20.3 to 1.20.4 (#2912)

Bumps [org.testcontainers:testcontainers-bom](https://github.com/testcontainers/testcontainers-java) from 1.20.3 to 1.20.4.
- [Release notes](https://github.com/testcontainers/testcontainers-java/releases)
- [Changelog](https://github.com/testcontainers/testcontainers-java/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testcontainers/testcontainers-java/compare/1.20.3...1.20.4)

---
updated-dependencies:
- dependency-name: org.testcontainers:testcontainers-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index f167ef1ac5..d6fd1191ef 100644
--- a/build.gradle
+++ b/build.gradle
@@ -69,7 +69,7 @@ ext {
 	springDataVersion = '2024.1.0'
 	springRetryVersion = '2.0.10'
 	springVersion = '6.2.0'
-	testcontainersVersion = '1.20.3'
+	testcontainersVersion = '1.20.4'
 
 	javaProjects = subprojects - project(':spring-amqp-bom')
 }

From c182d2adf205d43ebbf3ef700b0148d2b8ae7aca Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2024 22:38:21 -0500
Subject: [PATCH 093/111] Bump org.apache.logging.log4j:log4j-bom from 2.24.1
 to 2.24.2 (#2913)

Bumps [org.apache.logging.log4j:log4j-bom](https://github.com/apache/logging-log4j2) from 2.24.1 to 2.24.2.
- [Release notes](https://github.com/apache/logging-log4j2/releases)
- [Changelog](https://github.com/apache/logging-log4j2/blob/2.x/RELEASE-NOTES.adoc)
- [Commits](https://github.com/apache/logging-log4j2/compare/rel/2.24.1...rel/2.24.2)

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index d6fd1191ef..5bdd577d03 100644
--- a/build.gradle
+++ b/build.gradle
@@ -57,7 +57,7 @@ ext {
 	junit4Version = '4.13.2'
 	junitJupiterVersion = '5.11.3'
 	kotlinCoroutinesVersion = '1.8.1'
-	log4jVersion = '2.24.1'
+	log4jVersion = '2.24.2'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
 	micrometerVersion = '1.14.1'

From 0128f7e3bd59975d901a8181eb81ffa058c672b5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Dec 2024 13:33:32 -0500
Subject: [PATCH 094/111] Bump com.fasterxml.jackson:jackson-bom from 2.18.1 to
 2.18.2

Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.1 to 2.18.2.
- [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.1...jackson-bom-2.18.2)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson:jackson-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 5bdd577d03..a2056286a1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,7 +52,7 @@ ext {
 	commonsPoolVersion = '2.12.0'
 	hamcrestVersion = '3.0'
 	hibernateValidationVersion = '8.0.1.Final'
-	jacksonBomVersion = '2.18.1'
+	jacksonBomVersion = '2.18.2'
 	jaywayJsonPathVersion = '2.9.0'
 	junit4Version = '4.13.2'
 	junitJupiterVersion = '5.11.3'

From ced72edb6c0ed0b41a132207682699115a7c56c2 Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Tue, 3 Dec 2024 12:13:46 -0500
Subject: [PATCH 095/111] GH-2917: Add
 `AbstractConnectionFactory.setAddresses(List)`

Fixes: https://github.com/spring-projects/spring-amqp/issues/2917

In Spring Boot `3.4.0` the `org.springframework.boot.autoconfigure.amqp.RabbitProperties#getAddresses()`
returns a `List` while it previously returned a `String`.
This makes it incompatible with `AbstractConnectionFactory.setAddresses` which accepts a `String`.
Previously we could do `cachingConnectionFactory.setAddresses(rabbitProperties.getAddresses());`,
but now have to go with a `cachingConnectionFactory.setAddresses(String.join(",", rabbitProperties.getAddresses()))`

* Expose `AbstractConnectionFactory.setAddresses(List)` for the mentioned convenience to be able to use `List`
as an alternative to comma-separated string
---
 .../rabbit/connection/AbstractConnectionFactory.java  | 11 ++++++++++-
 .../connection/AbstractConnectionFactoryTests.java    |  3 ++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
index caa57d6c92..b7ecb1a80d 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactory.java
@@ -344,7 +344,16 @@ public int getPort() {
 
 	/**
 	 * Set addresses for clustering. This property overrides the host+port properties if not empty.
-	 * @param addresses list of addresses with form "host[:port],..."
+	 * @param addresses list of addresses in form {@code host[:port]}.
+	 * @since 3.2.1
+	 */
+	public void setAddresses(List addresses) {
+		Assert.notEmpty(addresses, "Addresses must not be empty");
+		setAddresses(String.join(",", addresses));
+	}
+	/**
+	 * Set addresses for clustering. This property overrides the host+port properties if not empty.
+	 * @param addresses list of addresses with form {@code host1[:port1],host2[:port2],...}.
 	 */
 	public void setAddresses(String addresses) {
 		this.lock.lock();
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
index e41ea8635d..097ddf9632 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/connection/AbstractConnectionFactoryTests.java
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.verify;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -110,7 +111,7 @@ public void onClose(Connection connection) {
 
 		verify(mockConnectionFactory, times(1)).newConnection(any(ExecutorService.class), anyString());
 
-		connectionFactory.setAddresses("foo:5672,bar:5672");
+		connectionFactory.setAddresses(List.of("foo:5672", "bar:5672"));
 		connectionFactory.setAddressShuffleMode(AddressShuffleMode.NONE);
 		con = connectionFactory.createConnection();
 		assertThat(called.get()).isEqualTo(1);

From 162ef4a60e31daeaf64f043063fed965ee4bc69b Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Fri, 6 Dec 2024 09:43:12 -0500
Subject: [PATCH 096/111] Attempt to fix race condition in the
 `CachingConnectionFactory`

There is a logic in the `CachingConnectionFactory.destroy()` where we wait for `inFlightAsyncCloses`.
However, it looks like we first close the main connection with all its channels.
Therefore, we may end up with a `ConcurrentModificationException` when we iterate channels list for clean up,
but in-flight requests still wait for their confirms, therefore they may come back to the cache meanwhile we are trying to clean up
---
 .../rabbit/connection/CachingConnectionFactory.java    |  4 ++--
 ...itTemplatePublisherCallbacksIntegration1Tests.java} |  4 ++--
 ...itTemplatePublisherCallbacksIntegration2Tests.java} |  8 ++++----
 ...itTemplatePublisherCallbacksIntegration3Tests.java} | 10 +++++-----
 4 files changed, 13 insertions(+), 13 deletions(-)
 rename spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/{RabbitTemplatePublisherCallbacksIntegrationTests.java => RabbitTemplatePublisherCallbacksIntegration1Tests.java} (99%)
 rename spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/{RabbitTemplatePublisherCallbacksIntegrationTests2.java => RabbitTemplatePublisherCallbacksIntegration2Tests.java} (96%)
 rename spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/{RabbitTemplatePublisherCallbacksIntegrationTests3.java => RabbitTemplatePublisherCallbacksIntegration3Tests.java} (95%)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
index 0aade48321..302b18a5cd 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/CachingConnectionFactory.java
@@ -861,8 +861,6 @@ private void refreshProxyConnection(ChannelCachingConnectionProxy connection) {
 	 */
 	@Override
 	public final void destroy() {
-		super.destroy();
-		resetConnection();
 		if (getContextStopped()) {
 			this.stopped = true;
 			this.connectionLock.lock();
@@ -890,6 +888,8 @@ public final void destroy() {
 				this.connectionLock.unlock();
 			}
 		}
+		super.destroy();
+		resetConnection();
 	}
 
 	/**
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration1Tests.java
similarity index 99%
rename from spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests.java
rename to spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration1Tests.java
index 1429b7f5e6..fef647063b 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration1Tests.java
@@ -95,8 +95,8 @@
  * @since 1.1
  *
  */
-@RabbitAvailable(queues = RabbitTemplatePublisherCallbacksIntegrationTests.ROUTE)
-public class RabbitTemplatePublisherCallbacksIntegrationTests {
+@RabbitAvailable(queues = RabbitTemplatePublisherCallbacksIntegration1Tests.ROUTE)
+public class RabbitTemplatePublisherCallbacksIntegration1Tests {
 
 	public static final String ROUTE = "test.queue.RabbitTemplatePublisherCallbacksIntegrationTests";
 
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests2.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration2Tests.java
similarity index 96%
rename from spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests2.java
rename to spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration2Tests.java
index 450c1566a8..06837b9895 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests2.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration2Tests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 the original author or authors.
+ * Copyright 2016-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,9 +41,9 @@
  * @since 1.6
  *
  */
-@RabbitAvailable(queues = { RabbitTemplatePublisherCallbacksIntegrationTests2.ROUTE,
-		RabbitTemplatePublisherCallbacksIntegrationTests2.ROUTE2 })
-public class RabbitTemplatePublisherCallbacksIntegrationTests2 {
+@RabbitAvailable(queues = { RabbitTemplatePublisherCallbacksIntegration2Tests.ROUTE,
+		RabbitTemplatePublisherCallbacksIntegration2Tests.ROUTE2 })
+public class RabbitTemplatePublisherCallbacksIntegration2Tests {
 
 	public static final String ROUTE = "test.queue.RabbitTemplatePublisherCallbacksIntegrationTests2";
 
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests3.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration3Tests.java
similarity index 95%
rename from spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests3.java
rename to spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration3Tests.java
index 8e7fcef70e..d9f1dddd47 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegrationTests3.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePublisherCallbacksIntegration3Tests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,10 +41,10 @@
  * @since 2.1
  *
  */
-@RabbitAvailable(queues = { RabbitTemplatePublisherCallbacksIntegrationTests3.QUEUE1,
-		RabbitTemplatePublisherCallbacksIntegrationTests3.QUEUE2,
-		RabbitTemplatePublisherCallbacksIntegrationTests3.QUEUE3 })
-public class RabbitTemplatePublisherCallbacksIntegrationTests3 {
+@RabbitAvailable(queues = { RabbitTemplatePublisherCallbacksIntegration3Tests.QUEUE1,
+		RabbitTemplatePublisherCallbacksIntegration3Tests.QUEUE2,
+		RabbitTemplatePublisherCallbacksIntegration3Tests.QUEUE3 })
+public class RabbitTemplatePublisherCallbacksIntegration3Tests {
 
 	public static final String QUEUE1 = "synthetic.nack";
 

From db59442ea26baad39044cc70baec5856a2f1bcc8 Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Thu, 12 Dec 2024 11:22:46 -0500
Subject: [PATCH 097/111] Add `@DirtiesContext` to tests to clean up app ctx
 cache

And attempt to mitigate out of memory error on CI/CD
---
 .../support/converter/Jackson2JsonMessageConverterTests.java  | 4 +++-
 .../support/converter/Jackson2XmlMessageConverterTests.java   | 4 +++-
 .../rabbit/stream/config/SuperStreamProvisioningTests.java    | 4 +++-
 .../rabbit/stream/listener/SuperStreamConcurrentSACTests.java | 4 +++-
 .../rabbit/stream/listener/SuperStreamSACTests.java           | 4 +++-
 .../amqp/rabbit/test/context/SpringRabbitTestTests.java       | 4 +++-
 .../amqp/rabbit/test/examples/TestRabbitTemplateTests.java    | 2 ++
 ...ContentTypeDelegatingMessageConverterIntegrationTests.java | 4 +++-
 .../amqp/rabbit/annotation/OptionalPayloadTests.java          | 4 +++-
 .../amqp/rabbit/listener/AsyncReplyToTests.java               | 4 +++-
 .../amqp/rabbit/listener/BrokerEventListenerTests.java        | 3 ++-
 .../springframework/amqp/rabbit/listener/DlqExpiryTests.java  | 4 +++-
 .../adapter/BatchMessagingMessageListenerAdapterTests.java    | 4 +++-
 .../amqp/rabbit/support/micrometer/ObservationTests.java      | 2 ++
 14 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2JsonMessageConverterTests.java b/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2JsonMessageConverterTests.java
index 37e274d314..574fecc06f 100644
--- a/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2JsonMessageConverterTests.java
+++ b/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2JsonMessageConverterTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.data.web.JsonPath;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 import org.springframework.util.MimeTypeUtils;
 
@@ -54,6 +55,7 @@
  * @author Artem Bilan
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class Jackson2JsonMessageConverterTests {
 
 	public static final String TRUSTED_PACKAGE = Jackson2JsonMessageConverterTests.class.getPackage().getName();
diff --git a/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2XmlMessageConverterTests.java b/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2XmlMessageConverterTests.java
index d5e3825a0c..836ee45ca0 100644
--- a/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2XmlMessageConverterTests.java
+++ b/spring-amqp/src/test/java/org/springframework/amqp/support/converter/Jackson2XmlMessageConverterTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2019 the original author or authors.
+ * Copyright 2018-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 import org.springframework.amqp.core.MessageProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
@@ -43,6 +44,7 @@
  * @since 2.1
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class Jackson2XmlMessageConverterTests {
 
 	public static final String TRUSTED_PACKAGE = Jackson2XmlMessageConverterTests.class.getPackage().getName();
diff --git a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/config/SuperStreamProvisioningTests.java b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/config/SuperStreamProvisioningTests.java
index b87daf8db8..75880c5e2d 100644
--- a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/config/SuperStreamProvisioningTests.java
+++ b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/config/SuperStreamProvisioningTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 /**
@@ -40,6 +41,7 @@
  *
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class SuperStreamProvisioningTests extends AbstractTestContainerTests {
 
 	@Test
diff --git a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamConcurrentSACTests.java b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamConcurrentSACTests.java
index c7d34dd83e..50e1ff1058 100644
--- a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamConcurrentSACTests.java
+++ b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamConcurrentSACTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022-2023 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.rabbit.stream.config.SuperStream;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.rabbitmq.stream.Environment;
@@ -49,6 +50,7 @@
  *
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class SuperStreamConcurrentSACTests extends AbstractTestContainerTests {
 
 	@Test
diff --git a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamSACTests.java b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamSACTests.java
index 1daaca2d33..a474f6926e 100644
--- a/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamSACTests.java
+++ b/spring-rabbit-stream/src/test/java/org/springframework/rabbit/stream/listener/SuperStreamSACTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022-2023 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,6 +45,7 @@
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 import org.springframework.rabbit.stream.config.SuperStream;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.rabbitmq.stream.Environment;
@@ -57,6 +58,7 @@
  *
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class SuperStreamSACTests extends AbstractTestContainerTests {
 
 	@Test
diff --git a/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/context/SpringRabbitTestTests.java b/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/context/SpringRabbitTestTests.java
index b4c2fc7e01..697e984a0f 100644
--- a/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/context/SpringRabbitTestTests.java
+++ b/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/context/SpringRabbitTestTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 /**
@@ -39,6 +40,7 @@
 @RabbitAvailable
 @SpringJUnitConfig
 @SpringRabbitTest
+@DirtiesContext
 public class SpringRabbitTestTests {
 
 	@Autowired
diff --git a/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/examples/TestRabbitTemplateTests.java b/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/examples/TestRabbitTemplateTests.java
index 4d8c69586b..6ee389b821 100644
--- a/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/examples/TestRabbitTemplateTests.java
+++ b/spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/examples/TestRabbitTemplateTests.java
@@ -39,6 +39,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.rabbitmq.client.AMQP;
@@ -53,6 +54,7 @@
  *
  */
 @SpringJUnitConfig
+@DirtiesContext
 public class TestRabbitTemplateTests {
 
 	@Autowired
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/ContentTypeDelegatingMessageConverterIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/ContentTypeDelegatingMessageConverterIntegrationTests.java
index 91a23421ba..3ac031bcd0 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/ContentTypeDelegatingMessageConverterIntegrationTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/ContentTypeDelegatingMessageConverterIntegrationTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 the original author or authors.
+ * Copyright 2020-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@
 import org.springframework.messaging.MessageHeaders;
 import org.springframework.messaging.handler.annotation.SendTo;
 import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 import org.springframework.util.MimeType;
 
@@ -54,6 +55,7 @@
  */
 @RabbitAvailable
 @SpringJUnitConfig
+@DirtiesContext
 public class ContentTypeDelegatingMessageConverterIntegrationTests {
 
 	@Autowired
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/OptionalPayloadTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/OptionalPayloadTests.java
index 1d5a476433..56790f4eab 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/OptionalPayloadTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/OptionalPayloadTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -52,6 +53,7 @@
  */
 @SpringJUnitConfig
 @RabbitAvailable(queues = { "op.1", "op.2" })
+@DirtiesContext
 public class OptionalPayloadTests {
 
 	@Test
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/AsyncReplyToTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/AsyncReplyToTests.java
index e5c43a5fd7..23e6bb17d5 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/AsyncReplyToTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/AsyncReplyToTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021-2022 the original author or authors.
+ * Copyright 2021-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.rabbitmq.client.Channel;
@@ -55,6 +56,7 @@
  */
 @SpringJUnitConfig
 @RabbitAvailable(queues = { "async1", "async2" })
+@DirtiesContext
 public class AsyncReplyToTests {
 
 	@Test
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/BrokerEventListenerTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/BrokerEventListenerTests.java
index 2541493c7a..d5473bc3cb 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/BrokerEventListenerTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/BrokerEventListenerTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2019 the original author or authors.
+ * Copyright 2018-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
  */
 @SpringJUnitConfig
 @RabbitAvailable
+@DirtiesContext
 public class BrokerEventListenerTests {
 
 	@Autowired
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/DlqExpiryTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/DlqExpiryTests.java
index 729a66e825..4b5d8ca51b 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/DlqExpiryTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/DlqExpiryTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2019 the original author or authors.
+ * Copyright 2018-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 /**
@@ -47,6 +48,7 @@
  */
 @RabbitAvailable
 @SpringJUnitConfig
+@DirtiesContext
 public class DlqExpiryTests {
 
 	@Autowired
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/BatchMessagingMessageListenerAdapterTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/BatchMessagingMessageListenerAdapterTests.java
index d12f1d5a51..978551e288 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/BatchMessagingMessageListenerAdapterTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/adapter/BatchMessagingMessageListenerAdapterTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022-2023 the original author or authors.
+ * Copyright 2022-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -57,6 +58,7 @@
  */
 @SpringJUnitConfig
 @RabbitAvailable(queues = "test.batchQueue")
+@DirtiesContext
 public class BatchMessagingMessageListenerAdapterTests {
 
 	@Test
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java
index fe1b38995a..0b6cc28325 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationTests.java
@@ -44,6 +44,7 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.lang.Nullable;
+import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
 import io.micrometer.common.KeyValues;
@@ -74,6 +75,7 @@
  */
 @SpringJUnitConfig
 @RabbitAvailable(queues = { "observation.testQ1", "observation.testQ2" })
+@DirtiesContext
 public class ObservationTests {
 
 	@Test

From 932492787d2a3974638aef0fc017a084545a382e Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Thu, 12 Dec 2024 12:11:29 -0500
Subject: [PATCH 098/111] GH-2914: Make `delivery_tag` as a high cardinality
 observation tag

Fixes: https://github.com/spring-projects/spring-amqp/issues/2914

The `delivery_tag` on consumer side is really per message,
so that makes too many metric timers when this property is exposed as a low cardinality tag.

* Fix `RabbitListenerObservation` moving the `ListenerLowCardinalityTags.DELIVERY_TAG` into the `ListenerHighCardinalityTags.DELIVERY_TAG`
* Leave `ListenerLowCardinalityTags.DELIVERY_TAG` as deprecated to avoid compatibility issues,
but exclude it from the `getLowCardinalityKeyNames()` implementation
---
 .../micrometer/RabbitListenerObservation.java | 51 ++++++++++++++++---
 .../ObservationIntegrationTests.java          |  7 ++-
 2 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
index a9bb6dabd8..47efa0be3a 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
@@ -16,6 +16,8 @@
 
 package org.springframework.amqp.rabbit.support.micrometer;
 
+import java.util.Arrays;
+
 import io.micrometer.common.KeyValues;
 import io.micrometer.common.docs.KeyName;
 import io.micrometer.observation.Observation.Context;
@@ -45,7 +47,14 @@ public Class> getDefaultConve
 
 		@Override
 		public KeyName[] getLowCardinalityKeyNames() {
-			return ListenerLowCardinalityTags.values();
+			return Arrays.stream(ListenerLowCardinalityTags.values())
+					.filter((key) -> !ListenerLowCardinalityTags.DELIVERY_TAG.equals(key))
+					.toArray(KeyName[]::new);
+		}
+
+		@Override
+		public KeyName[] getHighCardinalityKeyNames() {
+			return ListenerHighCardinalityTags.values();
 		}
 
 	};
@@ -83,8 +92,33 @@ public String asString() {
 
 		/**
 		 * The delivery tag.
+		 * After deprecation this key is not exposed as a low cardinality tag.
 		 *
 		 * @since 3.2
+		 *
+		 * @deprecated in favor of {@link ListenerHighCardinalityTags#DELIVERY_TAG}
+		 */
+		@Deprecated(since = "3.2.1", forRemoval = true)
+		DELIVERY_TAG {
+
+			@Override
+			public String asString() {
+				return "messaging.rabbitmq.message.delivery_tag";
+			}
+
+		}
+
+	}
+
+	/**
+	 * High cardinality tags.
+	 *
+	 * @since 3.2.1
+	 */
+	public enum ListenerHighCardinalityTags implements KeyName {
+
+		/**
+		 * The delivery tag.
 		 */
 		DELIVERY_TAG {
 
@@ -97,6 +131,7 @@ public String asString() {
 
 	}
 
+
 	/**
 	 * Default {@link RabbitListenerObservationConvention} for Rabbit listener key values.
 	 */
@@ -112,12 +147,16 @@ public static class DefaultRabbitListenerObservationConvention implements Rabbit
 		public KeyValues getLowCardinalityKeyValues(RabbitMessageReceiverContext context) {
 			final var messageProperties = context.getCarrier().getMessageProperties();
 			return KeyValues.of(
-					RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(), context.getListenerId(),
+					RabbitListenerObservation.ListenerLowCardinalityTags.LISTENER_ID.asString(),
+					context.getListenerId(),
 					RabbitListenerObservation.ListenerLowCardinalityTags.DESTINATION_NAME.asString(),
-					messageProperties.getConsumerQueue(),
-					RabbitListenerObservation.ListenerLowCardinalityTags.DELIVERY_TAG.asString(),
-					String.valueOf(messageProperties.getDeliveryTag())
-			);
+					messageProperties.getConsumerQueue());
+		}
+
+		@Override
+		public KeyValues getHighCardinalityKeyValues(RabbitMessageReceiverContext context) {
+			return KeyValues.of(RabbitListenerObservation.ListenerHighCardinalityTags.DELIVERY_TAG.asString(),
+					String.valueOf(context.getCarrier().getMessageProperties().getDeliveryTag()));
 		}
 
 		@Override
diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java
index 920deec403..48e981c2f1 100644
--- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java
+++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/support/micrometer/ObservationIntegrationTests.java
@@ -47,6 +47,7 @@
 /**
  * @author Artem Bilan
  * @author Gary Russell
+ *
  * @since 3.0
  */
 @RabbitAvailable(queues = { "int.observation.testQ1", "int.observation.testQ2" })
@@ -120,15 +121,13 @@ public SampleTestRunnerConsumer yourCode() {
 					.hasTimerWithNameAndTags("spring.rabbit.listener",
 							KeyValues.of(
 									KeyValue.of("spring.rabbit.listener.id", "obs1"),
-									KeyValue.of("messaging.destination.name", "int.observation.testQ1"),
-									KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1")
+									KeyValue.of("messaging.destination.name", "int.observation.testQ1")
 							)
 					)
 					.hasTimerWithNameAndTags("spring.rabbit.listener",
 							KeyValues.of(
 									KeyValue.of("spring.rabbit.listener.id", "obs2"),
-									KeyValue.of("messaging.destination.name", "int.observation.testQ2"),
-									KeyValue.of("messaging.rabbitmq.message.delivery_tag", "1")
+									KeyValue.of("messaging.destination.name", "int.observation.testQ2")
 							)
 					);
 		};

From b6e7235e6e4e100ded89157b7217844143add7c6 Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Thu, 12 Dec 2024 12:18:27 -0500
Subject: [PATCH 099/111] Fix `RabbitListenerObservation` for docs generation
 compatibility

---
 .../support/micrometer/RabbitListenerObservation.java       | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
index 47efa0be3a..19e75baf0b 100644
--- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
+++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/micrometer/RabbitListenerObservation.java
@@ -16,8 +16,6 @@
 
 package org.springframework.amqp.rabbit.support.micrometer;
 
-import java.util.Arrays;
-
 import io.micrometer.common.KeyValues;
 import io.micrometer.common.docs.KeyName;
 import io.micrometer.observation.Observation.Context;
@@ -47,9 +45,7 @@ public Class> getDefaultConve
 
 		@Override
 		public KeyName[] getLowCardinalityKeyNames() {
-			return Arrays.stream(ListenerLowCardinalityTags.values())
-					.filter((key) -> !ListenerLowCardinalityTags.DELIVERY_TAG.equals(key))
-					.toArray(KeyName[]::new);
+			return ListenerLowCardinalityTags.values();
 		}
 
 		@Override

From 6da994aba93b38826654dcf86440eb490eba59bc Mon Sep 17 00:00:00 2001
From: Artem Bilan 
Date: Thu, 12 Dec 2024 12:22:02 -0500
Subject: [PATCH 100/111] GH-2895: Mention `endpoint.setId()` in the
 `registration.adoc`

Fixes: https://github.com/spring-projects/spring-amqp/issues/2895

Since `id` is required for the `SimpleRabbitListenerEndpoint` definition,
it is better to show it in the docs sample and mention its importance.
---
 .../async-annotation-driven/registration.adoc                  | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/registration.adoc b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/registration.adoc
index d1458af838..46db7e95b5 100644
--- a/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/registration.adoc
+++ b/src/reference/antora/modules/ROOT/pages/amqp/receiving-messages/async-annotation-driven/registration.adoc
@@ -14,6 +14,7 @@ public class AppConfig implements RabbitListenerConfigurer {
     @Override
     public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
         SimpleRabbitListenerEndpoint endpoint = new SimpleRabbitListenerEndpoint();
+		endpoint.setId("someRabbitListenerEndpoint");
         endpoint.setQueueNames("anotherQueue");
         endpoint.setMessageListener(message -> {
             // processing
@@ -25,5 +26,7 @@ public class AppConfig implements RabbitListenerConfigurer {
 
 In the preceding example, we used `SimpleRabbitListenerEndpoint`, which provides the actual `MessageListener` to invoke, but you could just as well build your own endpoint variant to describe a custom invocation mechanism.
 
+NOTE: the `id` property is required for `SimpleRabbitListenerEndpoint` definition.
+
 It should be noted that you could just as well skip the use of `@RabbitListener` altogether and register your endpoints programmatically through `RabbitListenerConfigurer`.
 

From 5d7c382d8ef83f547f685244338e884f5de2badb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:19:00 +0000
Subject: [PATCH 101/111] Bump io.micrometer:micrometer-bom from 1.14.1 to
 1.14.2 (#2927)

Bumps [io.micrometer:micrometer-bom](https://github.com/micrometer-metrics/micrometer) from 1.14.1 to 1.14.2.
- [Release notes](https://github.com/micrometer-metrics/micrometer/releases)
- [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.1...v1.14.2)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index a2056286a1..0d3689a3e7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,7 +60,7 @@ ext {
 	log4jVersion = '2.24.2'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
-	micrometerVersion = '1.14.1'
+	micrometerVersion = '1.14.2'
 	micrometerTracingVersion = '1.4.0'
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'

From 40bded4550e40cbe332294a9676eda5cc598bb96 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:19:12 +0000
Subject: [PATCH 102/111] Bump org.hibernate.validator:hibernate-validator
 (#2922)

Bumps the development-dependencies group with 1 update: [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator).


Updates `org.hibernate.validator:hibernate-validator` from 8.0.1.Final to 8.0.2.Final
- [Changelog](https://github.com/hibernate/hibernate-validator/blob/8.0.2.Final/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-validator/compare/8.0.1.Final...8.0.2.Final)

---
updated-dependencies:
- dependency-name: org.hibernate.validator:hibernate-validator
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 0d3689a3e7..b10f980174 100644
--- a/build.gradle
+++ b/build.gradle
@@ -51,7 +51,7 @@ ext {
 	commonsHttpClientVersion = '5.4.1'
 	commonsPoolVersion = '2.12.0'
 	hamcrestVersion = '3.0'
-	hibernateValidationVersion = '8.0.1.Final'
+	hibernateValidationVersion = '8.0.2.Final'
 	jacksonBomVersion = '2.18.2'
 	jaywayJsonPathVersion = '2.9.0'
 	junit4Version = '4.13.2'

From 12a892ee77981f325104192fbd97fa7770677432 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:19:48 +0000
Subject: [PATCH 103/111] Bump org.springframework.retry:spring-retry from
 2.0.10 to 2.0.11 (#2923)

Bumps [org.springframework.retry:spring-retry](https://github.com/spring-projects/spring-retry) from 2.0.10 to 2.0.11.
- [Release notes](https://github.com/spring-projects/spring-retry/releases)
- [Commits](https://github.com/spring-projects/spring-retry/compare/v2.0.10...v2.0.11)

---
updated-dependencies:
- dependency-name: org.springframework.retry:spring-retry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index b10f980174..4c4f9094be 100644
--- a/build.gradle
+++ b/build.gradle
@@ -67,7 +67,7 @@ ext {
 	rabbitmqVersion = '5.22.0'
 	reactorVersion = '2024.0.0'
 	springDataVersion = '2024.1.0'
-	springRetryVersion = '2.0.10'
+	springRetryVersion = '2.0.11'
 	springVersion = '6.2.0'
 	testcontainersVersion = '1.20.4'
 

From 2bbd4929c130f6870a020fa819b3f3e524d3baea Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:19:58 +0000
Subject: [PATCH 104/111] Bump org.apache.logging.log4j:log4j-bom from 2.24.2
 to 2.24.3 (#2925)

Bumps [org.apache.logging.log4j:log4j-bom](https://github.com/apache/logging-log4j2) from 2.24.2 to 2.24.3.
- [Release notes](https://github.com/apache/logging-log4j2/releases)
- [Changelog](https://github.com/apache/logging-log4j2/blob/2.x/RELEASE-NOTES.adoc)
- [Commits](https://github.com/apache/logging-log4j2/compare/rel/2.24.2...rel/2.24.3)

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 4c4f9094be..8eba02a4c4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -57,7 +57,7 @@ ext {
 	junit4Version = '4.13.2'
 	junitJupiterVersion = '5.11.3'
 	kotlinCoroutinesVersion = '1.8.1'
-	log4jVersion = '2.24.2'
+	log4jVersion = '2.24.3'
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
 	micrometerVersion = '1.14.2'

From c63752419a0b5f5f87b1d782d2a558f509bb1005 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:20:06 +0000
Subject: [PATCH 105/111] Bump io.projectreactor:reactor-bom from 2024.0.0 to
 2024.0.1 (#2924)

Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2024.0.0 to 2024.0.1.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2024.0.0...2024.0.1)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 8eba02a4c4..ed6642aeeb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -65,7 +65,7 @@ ext {
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'
-	reactorVersion = '2024.0.0'
+	reactorVersion = '2024.0.1'
 	springDataVersion = '2024.1.0'
 	springRetryVersion = '2.0.11'
 	springVersion = '6.2.0'

From 0bca0206aa0f62d76a3a4e9bbad5c415540f333f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:23:29 +0000
Subject: [PATCH 106/111] Bump io.micrometer:micrometer-tracing-bom from 1.4.0
 to 1.4.1 (#2929)

Bumps [io.micrometer:micrometer-tracing-bom](https://github.com/micrometer-metrics/tracing) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/micrometer-metrics/tracing/releases)
- [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: io.micrometer:micrometer-tracing-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index ed6642aeeb..587d5e3af2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -61,7 +61,7 @@ ext {
 	logbackVersion = '1.5.12'
 	micrometerDocsVersion = '1.0.4'
 	micrometerVersion = '1.14.2'
-	micrometerTracingVersion = '1.4.0'
+	micrometerTracingVersion = '1.4.1'
 	mockitoVersion = '5.14.2'
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'

From 4b72f763305843caff3739a0528b60599a0fba3a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:23:47 +0000
Subject: [PATCH 107/111] Bump org.springframework:spring-framework-bom from
 6.2.0 to 6.2.1 (#2928)

Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.0...v6.2.1)

---
updated-dependencies:
- dependency-name: org.springframework:spring-framework-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 587d5e3af2..19e89a49ed 100644
--- a/build.gradle
+++ b/build.gradle
@@ -68,7 +68,7 @@ ext {
 	reactorVersion = '2024.0.1'
 	springDataVersion = '2024.1.0'
 	springRetryVersion = '2.0.11'
-	springVersion = '6.2.0'
+	springVersion = '6.2.1'
 	testcontainersVersion = '1.20.4'
 
 	javaProjects = subprojects - project(':spring-amqp-bom')

From 1c49e579064152ad9730d24387336ccb32357f89 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 14 Dec 2024 02:24:00 +0000
Subject: [PATCH 108/111] Bump org.springframework.data:spring-data-bom from
 2024.1.0 to 2024.1.1 (#2926)

Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.0 to 2024.1.1.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.0...2024.1.1)

---
updated-dependencies:
- dependency-name: org.springframework.data:spring-data-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 19e89a49ed..02b67b3adc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -66,7 +66,7 @@ ext {
 	rabbitmqStreamVersion = '0.18.0'
 	rabbitmqVersion = '5.22.0'
 	reactorVersion = '2024.0.1'
-	springDataVersion = '2024.1.0'
+	springDataVersion = '2024.1.1'
 	springRetryVersion = '2.0.11'
 	springVersion = '6.2.1'
 	testcontainersVersion = '1.20.4'

From ede2d209ff7168f32c0d7633c98745e5746b0c71 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 16 Dec 2024 18:40:59 +0000
Subject: [PATCH 109/111] Bump org.junit:junit-bom from 5.11.3 to 5.11.4
 (#2931)

Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.3 to 5.11.4.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.11.3...r5.11.4)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] 
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 02b67b3adc..5877efe080 100644
--- a/build.gradle
+++ b/build.gradle
@@ -55,7 +55,7 @@ ext {
 	jacksonBomVersion = '2.18.2'
 	jaywayJsonPathVersion = '2.9.0'
 	junit4Version = '4.13.2'
-	junitJupiterVersion = '5.11.3'
+	junitJupiterVersion = '5.11.4'
 	kotlinCoroutinesVersion = '1.8.1'
 	log4jVersion = '2.24.3'
 	logbackVersion = '1.5.12'

From 085d21ef9d966a0f222061bb3d2c5952ce286f00 Mon Sep 17 00:00:00 2001
From: Spring Builds 
Date: Mon, 16 Dec 2024 19:04:37 +0000
Subject: [PATCH 110/111] [artifactory-release] Release version 3.2.1

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 2b07979582..2e0f03694f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-version=3.2.1-SNAPSHOT
+version=3.2.1
 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8
 org.gradle.daemon=true
 org.gradle.caching=true

From d139c981c24cf94f1baa1f50a4ad7958873fab1c Mon Sep 17 00:00:00 2001
From: Spring Builds 
Date: Mon, 16 Dec 2024 19:04:37 +0000
Subject: [PATCH 111/111] [artifactory-release] Next development version

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 2e0f03694f..8e33f5cdb5 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
-version=3.2.1
+version=3.2.2-SNAPSHOT
 org.gradle.jvmargs=-Xms512m -Xmx4g -Dfile.encoding=UTF-8
 org.gradle.daemon=true
 org.gradle.caching=true