Skip to content

Commit a00789a

Browse files
fablakesongaryrussell
authored andcommitted
GH-2441: Merged Annotations with RetryableTopic
Resolves #2441 Add merged annotations support to RetryableTopic Add merged attribute to meta-annotation example Add https to license url Docs.
1 parent 954b622 commit a00789a

File tree

6 files changed

+40
-7
lines changed

6 files changed

+40
-7
lines changed

spring-kafka-docs/src/main/asciidoc/retrytopic.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,23 @@ public void processMessage(MyPojo message) {
8282
NOTE: If you don't specify a kafkaTemplate name a bean with name `defaultRetryTopicKafkaTemplate` will be looked up.
8383
If no bean is found an exception is thrown.
8484

85+
Starting with version 3.0, the `@RetryableTopic` annotation can be used as a meta-annotation on custom annotations; for example:
86+
87+
====
88+
[source, java]
89+
----
90+
@Target({ElementType.METHOD})
91+
@Retention(RetentionPolicy.RUNTIME)
92+
@RetryableTopic
93+
static @interface MetaAnnotatedRetryableTopic {
94+
95+
@AliasFor(attribute = "concurrency", annotation = RetryableTopic.class)
96+
String parallelism() default "3";
97+
98+
}
99+
----
100+
====
101+
85102
===== Using `RetryTopicConfiguration` beans
86103

87104
You can also configure the non-blocking retry support by creating `RetryTopicConfiguration` beans in a `@Configuration` annotated class.

spring-kafka-docs/src/main/asciidoc/whats-new.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ The bootstrapping of <<retry-topic>> infrastructure beans has changed in this re
3838

3939
You can now set a different `concurrency` for the retry containers; by default, the concurrency is the same as the main container.
4040

41+
`@RetryableTopic` can now be used as a meta-annotation on custom annotations, including support for `@AliasFor` properties.
42+
4143
See <<retry-config>> for more information.
4244

4345
You can now configure multiple `@RetryableTopic` listeners on the same topic in the same application context.

spring-kafka/src/main/java/org/springframework/kafka/annotation/RetryTopicConfigurationProvider.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727
import org.springframework.beans.factory.config.BeanExpressionResolver;
2828
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
2929
import org.springframework.context.expression.StandardBeanExpressionResolver;
30-
import org.springframework.core.annotation.AnnotationUtils;
30+
import org.springframework.core.annotation.MergedAnnotation;
31+
import org.springframework.core.annotation.MergedAnnotations;
32+
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
33+
import org.springframework.core.annotation.RepeatableContainers;
3134
import org.springframework.core.log.LogAccessor;
3235
import org.springframework.kafka.retrytopic.RetryTopicConfiguration;
3336

@@ -88,7 +91,11 @@ public RetryTopicConfigurationProvider(BeanFactory beanFactory, BeanExpressionRe
8891
this.expressionContext = expressionContext;
8992
}
9093
public RetryTopicConfiguration findRetryConfigurationFor(String[] topics, Method method, Object bean) {
91-
RetryableTopic annotation = AnnotationUtils.findAnnotation(method, RetryableTopic.class);
94+
RetryableTopic annotation = MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY,
95+
RepeatableContainers.none())
96+
.get(RetryableTopic.class)
97+
.synthesize(MergedAnnotation::isPresent)
98+
.orElse(null);
9299
return annotation != null
93100
? new RetryableTopicAnnotationProcessor(this.beanFactory, this.resolver, this.expressionContext)
94101
.processAnnotation(topics, method, annotation, bean)

spring-kafka/src/main/java/org/springframework/kafka/retrytopic/RetryTopicConfigurer.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,13 @@
150150
*</pre>
151151
* <p> Or through meta-annotations, such as:
152152
* <pre>
153-
* <code>@RetryableTopic(attempts = 3,
154-
* backoff = @Backoff(delay = 700, maxDelay = 12000, multiplier = 3))</code>
155-
* <code>public @interface WithExponentialBackoffRetry { }</code>
153+
* <code>@RetryableTopic(backoff = @Backoff(delay = 700, maxDelay = 12000, multiplier = 3))</code>
154+
* <code>public @interface WithExponentialBackoffRetry {</code>
155+
* <code> {@literal @}AliasFor(attribute = "attempts", annotation = RetryableTopic.class)
156+
* String retries();
157+
* }</code>
156158
*
157-
* <code>@WithExponentialBackoffRetry</code>
159+
* <code>@WithExponentialBackoffRetry(retries = "3")</code>
158160
* <code>@KafkaListener(topics = "my-annotated-topic")
159161
* public void processMessage(MyPojo message) {
160162
* // ... message processing

spring-kafka/src/test/java/org/springframework/kafka/listener/ErrorHandlingCoverageTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,

spring-kafka/src/test/java/org/springframework/kafka/retrytopic/RetryTopicConfigurationProviderTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.mockito.junit.jupiter.MockitoExtension;
3939

4040
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
41+
import org.springframework.core.annotation.AliasFor;
4142
import org.springframework.kafka.annotation.RetryTopicConfigurationProvider;
4243
import org.springframework.kafka.annotation.RetryableTopic;
4344
import org.springframework.kafka.core.KafkaOperations;
@@ -155,6 +156,8 @@ void shouldProvideFromMetaAnnotation() {
155156

156157
// then
157158
then(this.beanFactory).should(times(0)).getBeansOfType(RetryTopicConfiguration.class);
159+
assertThat(configuration.getConcurrency()).isEqualTo(3);
160+
158161
}
159162

160163
@Test
@@ -182,6 +185,8 @@ public void nonAnnotatedMethod() {
182185
@Retention(RetentionPolicy.RUNTIME)
183186
@RetryableTopic
184187
static @interface MetaAnnotatedRetryableTopic {
188+
@AliasFor(attribute = "concurrency", annotation = RetryableTopic.class)
189+
String parallelism() default "3";
185190
}
186191

187192
@MetaAnnotatedRetryableTopic

0 commit comments

Comments
 (0)