Skip to content

Commit ef5db30

Browse files
EddieChoChoartembilan
authored andcommitted
GH-8703: Fix MessagingAnnotationPP for AOT
Fixes #8703 * Instantiate a `MessagingAnnotationBeanPostProcessor` via factory method from `MessagingAnnotationPostProcessor` avoiding extra code generation on an explicitly provided complex `Map` for bean definition property * Fix test to react properly to a new logic of `MessagingAnnotationBeanPostProcessor` bean registration
1 parent ba6d35d commit ef5db30

12 files changed

+73
-71
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.integration.config;
1818

19+
import java.beans.Introspector;
20+
1921
import org.springframework.beans.factory.config.BeanDefinition;
2022
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2123
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -99,19 +101,28 @@ private void registerIntegrationConfigurationBeanFactoryPostProcessor(BeanDefini
99101

100102
/**
101103
* Register {@link MessagingAnnotationPostProcessor} and
102-
* {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor},
104+
* {@link MessagingAnnotationBeanPostProcessor},
103105
* if necessary.
104-
* Inject {@code defaultPublishedChannel} from provided {@link AnnotationMetadata}, if any.
105106
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s.
107+
* @see MessagingAnnotationPostProcessor#messagingAnnotationBeanPostProcessor()
106108
*/
107109
private void registerMessagingAnnotationPostProcessors(BeanDefinitionRegistry registry) {
108110
if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) {
109-
BeanDefinitionBuilder builder =
111+
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME,
110112
BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class)
111-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
113+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
114+
.getBeanDefinition());
115+
}
112116

113-
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME,
114-
builder.getBeanDefinition());
117+
118+
String beanName = Introspector.decapitalize(MessagingAnnotationBeanPostProcessor.class.getName());
119+
if (!registry.containsBeanDefinition(beanName)) {
120+
registry.registerBeanDefinition(beanName,
121+
BeanDefinitionBuilder.genericBeanDefinition()
122+
.setFactoryMethodOnBean("messagingAnnotationBeanPostProcessor",
123+
IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)
124+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
125+
.getBeanDefinition());
115126
}
116127
}
117128

spring-integration-core/src/main/java/org/springframework/integration/config/MessagingAnnotationBeanPostProcessor.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,13 @@ public class MessagingAnnotationBeanPostProcessor
6565

6666
private final List<Runnable> methodsToPostProcessAfterContextInitialization = new ArrayList<>();
6767

68-
private final BeanDefinitionRegistry registry;
69-
7068
private ConfigurableListableBeanFactory beanFactory;
7169

7270
private volatile boolean initialized;
7371

74-
public MessagingAnnotationBeanPostProcessor(BeanDefinitionRegistry registry,
72+
public MessagingAnnotationBeanPostProcessor(
7573
Map<Class<? extends Annotation>, MethodAnnotationPostProcessor<?>> postProcessors) {
7674

77-
this.registry = registry;
7875
this.postProcessors = postProcessors;
7976
}
8077

@@ -187,13 +184,12 @@ private void postProcessMethodAndRegisterEndpointIfAny(Object bean, String beanN
187184

188185
String endpointBeanName = generateBeanName(beanName, method, annotationType);
189186
endpoint.setBeanName(endpointBeanName);
190-
this.registry.registerBeanDefinition(endpointBeanName,
187+
((BeanDefinitionRegistry) this.beanFactory).registerBeanDefinition(endpointBeanName,
191188
new RootBeanDefinition((Class<AbstractEndpoint>) endpoint.getClass(), () -> endpoint));
192189
this.beanFactory.getBean(endpointBeanName);
193190
}
194191
}
195192

196-
197193
protected String generateBeanName(String originalBeanName, Method method,
198194
Class<? extends Annotation> annotationType) {
199195

spring-integration-core/src/main/java/org/springframework/integration/config/MessagingAnnotationPostProcessor.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.integration.config;
1818

19-
import java.beans.Introspector;
2019
import java.lang.annotation.Annotation;
2120
import java.util.HashMap;
2221
import java.util.List;
@@ -29,7 +28,6 @@
2928
import org.springframework.beans.factory.config.BeanDefinition;
3029
import org.springframework.beans.factory.config.BeanPostProcessor;
3130
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
32-
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3331
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3432
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
3533
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
@@ -91,14 +89,6 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t
9189
.map(BeanFactoryAware.class::cast)
9290
.forEach((processor) -> processor.setBeanFactory((BeanFactory) this.registry));
9391

94-
this.registry.registerBeanDefinition(
95-
Introspector.decapitalize(MessagingAnnotationBeanPostProcessor.class.getName()),
96-
BeanDefinitionBuilder.rootBeanDefinition(MessagingAnnotationBeanPostProcessor.class)
97-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
98-
.addConstructorArgValue(this.registry)
99-
.addConstructorArgValue(this.postProcessors)
100-
.getBeanDefinition());
101-
10292
String[] beanNames = registry.getBeanDefinitionNames();
10393

10494
for (String beanName : beanNames) {
@@ -111,6 +101,16 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t
111101
}
112102
}
113103

104+
/**
105+
* The factory method for {@link MessagingAnnotationBeanPostProcessor} based
106+
* on the environment from this {@link MessagingAnnotationPostProcessor}.
107+
* @return the {@link MessagingAnnotationBeanPostProcessor} instance based on {@link #postProcessors}.
108+
* @since 6.2
109+
*/
110+
public MessagingAnnotationBeanPostProcessor messagingAnnotationBeanPostProcessor() {
111+
return new MessagingAnnotationBeanPostProcessor(this.postProcessors);
112+
}
113+
114114
private void processCandidate(String beanName, AnnotatedBeanDefinition beanDefinition) {
115115
MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();
116116
MergedAnnotations annotations = methodMetadata.getAnnotations(); // NOSONAR

spring-integration-core/src/test/java/org/springframework/integration/bus/DirectChannelSubscriptionTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import org.springframework.integration.annotation.ServiceActivator;
2525
import org.springframework.integration.channel.DirectChannel;
2626
import org.springframework.integration.channel.QueueChannel;
27-
import org.springframework.integration.config.MessagingAnnotationPostProcessor;
27+
import org.springframework.integration.config.IntegrationRegistrar;
2828
import org.springframework.integration.context.IntegrationContextUtils;
2929
import org.springframework.integration.endpoint.EventDrivenConsumer;
3030
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
@@ -38,6 +38,7 @@
3838

3939
import static org.assertj.core.api.Assertions.assertThat;
4040
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
41+
import static org.mockito.Mockito.mock;
4142

4243
/**
4344
* @author Mark Fisher
@@ -54,7 +55,7 @@ public class DirectChannelSubscriptionTests {
5455

5556
@BeforeEach
5657
public void setupChannels() {
57-
this.context.registerBean(MessagingAnnotationPostProcessor.class);
58+
new IntegrationRegistrar().registerBeanDefinitions(mock(), this.context.getDefaultListableBeanFactory());
5859
this.context.registerChannel("sourceChannel", this.sourceChannel);
5960
this.context.registerChannel("targetChannel", this.targetChannel);
6061
}

spring-integration-core/src/test/java/org/springframework/integration/config/ServiceActivatorAnnotationPostProcessorTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
import org.springframework.messaging.support.GenericMessage;
3232

3333
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.mockito.Mockito.mock;
3435

3536
/**
3637
* @author Mark Fisher
@@ -42,8 +43,7 @@ public class ServiceActivatorAnnotationPostProcessorTests {
4243
public void testAnnotatedMethod() throws InterruptedException {
4344
CountDownLatch latch = new CountDownLatch(1);
4445
try (TestApplicationContext context = TestUtils.createTestApplicationContext()) {
45-
RootBeanDefinition postProcessorDef = new RootBeanDefinition(MessagingAnnotationPostProcessor.class);
46-
context.registerBeanDefinition("postProcessor", postProcessorDef);
46+
new IntegrationRegistrar().registerBeanDefinitions(mock(), context.getDefaultListableBeanFactory());
4747
context.registerBeanDefinition("testChannel", new RootBeanDefinition(DirectChannel.class));
4848
RootBeanDefinition beanDefinition = new RootBeanDefinition(SimpleServiceActivatorAnnotationTestBean.class);
4949
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(latch);

spring-integration-core/src/test/java/org/springframework/integration/config/annotation/CustomMessagingAnnotationTests.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@
3333
import org.springframework.beans.DirectFieldAccessor;
3434
import org.springframework.beans.factory.annotation.Autowired;
3535
import org.springframework.beans.factory.annotation.Qualifier;
36-
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3736
import org.springframework.context.annotation.Bean;
3837
import org.springframework.context.annotation.Configuration;
3938
import org.springframework.core.annotation.AnnotationUtils;
@@ -103,9 +102,7 @@ public void testLogAnnotation() {
103102
public static class Config {
104103

105104
@Bean(name = IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)
106-
public static MessagingAnnotationPostProcessor messagingAnnotationPostProcessor(
107-
ConfigurableListableBeanFactory beanFactory) {
108-
105+
public static MessagingAnnotationPostProcessor messagingAnnotationPostProcessor() {
109106
MessagingAnnotationPostProcessor messagingAnnotationPostProcessor = new MessagingAnnotationPostProcessor();
110107
messagingAnnotationPostProcessor.
111108
addMessagingAnnotationPostProcessor(Logging.class, new LogAnnotationPostProcessor());

spring-integration-core/src/test/java/org/springframework/integration/config/annotation/FilterAnnotationPostProcessorTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import org.springframework.integration.annotation.MessageEndpoint;
2828
import org.springframework.integration.channel.DirectChannel;
2929
import org.springframework.integration.channel.QueueChannel;
30+
import org.springframework.integration.config.IntegrationRegistrar;
3031
import org.springframework.integration.config.MessagingAnnotationBeanPostProcessor;
31-
import org.springframework.integration.config.MessagingAnnotationPostProcessor;
3232
import org.springframework.integration.endpoint.EventDrivenConsumer;
3333
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
3434
import org.springframework.integration.test.util.TestUtils;
@@ -38,6 +38,7 @@
3838

3939
import static org.assertj.core.api.Assertions.assertThat;
4040
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
41+
import static org.mockito.Mockito.mock;
4142

4243
/**
4344
* @author Mark Fisher
@@ -56,7 +57,7 @@ public class FilterAnnotationPostProcessorTests {
5657

5758
@BeforeEach
5859
public void init() {
59-
this.context.registerBean(MessagingAnnotationPostProcessor.class);
60+
new IntegrationRegistrar().registerBeanDefinitions(mock(), this.context.getDefaultListableBeanFactory());
6061
this.context.registerChannel("input", this.inputChannel);
6162
this.context.registerChannel("output", this.outputChannel);
6263
}

spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorTests.java

+19-23
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
import org.springframework.integration.annotation.Transformer;
3535
import org.springframework.integration.channel.DirectChannel;
3636
import org.springframework.integration.channel.QueueChannel;
37+
import org.springframework.integration.config.IntegrationRegistrar;
3738
import org.springframework.integration.config.MessagingAnnotationBeanPostProcessor;
38-
import org.springframework.integration.config.MessagingAnnotationPostProcessor;
3939
import org.springframework.integration.endpoint.AbstractEndpoint;
4040
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
4141
import org.springframework.integration.support.MessageBuilder;
@@ -49,6 +49,7 @@
4949
import org.springframework.messaging.support.GenericMessage;
5050

5151
import static org.assertj.core.api.Assertions.assertThat;
52+
import static org.mockito.Mockito.mock;
5253

5354
/**
5455
* @author Mark Fisher
@@ -59,10 +60,9 @@ public class MessagingAnnotationPostProcessorTests {
5960

6061
@Test
6162
public void serviceActivatorAnnotation() {
62-
TestApplicationContext context = TestUtils.createTestApplicationContext();
63+
TestApplicationContext context = createTestApplicationContext();
6364
DirectChannel inputChannel = new DirectChannel();
6465
context.registerChannel("inputChannel", inputChannel);
65-
context.registerBean(MessagingAnnotationPostProcessor.class);
6666
context.refresh();
6767

6868
MessagingAnnotationBeanPostProcessor postProcessor = context.getBean(MessagingAnnotationBeanPostProcessor.class);
@@ -134,8 +134,7 @@ public void typeConvertingHandler() {
134134

135135
@Test
136136
public void outboundOnlyServiceActivator() throws InterruptedException {
137-
TestApplicationContext context = TestUtils.createTestApplicationContext();
138-
context.registerBean(MessagingAnnotationPostProcessor.class);
137+
TestApplicationContext context = createTestApplicationContext();
139138
context.registerChannel("testChannel", new DirectChannel());
140139
CountDownLatch latch = new CountDownLatch(1);
141140
OutboundOnlyTestBean testBean = new OutboundOnlyTestBean(latch);
@@ -144,16 +143,14 @@ public void outboundOnlyServiceActivator() throws InterruptedException {
144143
DestinationResolver<MessageChannel> channelResolver = new BeanFactoryChannelResolver(context);
145144
MessageChannel testChannel = channelResolver.resolveDestination("testChannel");
146145
testChannel.send(new GenericMessage<>("foo"));
147-
latch.await(1000, TimeUnit.MILLISECONDS);
148-
assertThat(latch.getCount()).isEqualTo(0);
146+
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
149147
assertThat(testBean.getMessageText()).isEqualTo("foo");
150148
context.close();
151149
}
152150

153151
@Test
154152
public void testChannelResolution() {
155-
TestApplicationContext context = TestUtils.createTestApplicationContext();
156-
context.registerBean(MessagingAnnotationPostProcessor.class);
153+
TestApplicationContext context = createTestApplicationContext();
157154
DirectChannel inputChannel = new DirectChannel();
158155
QueueChannel outputChannel = new QueueChannel();
159156
DirectChannel eventBus = new DirectChannel();
@@ -177,8 +174,7 @@ public void testChannelResolution() {
177174

178175
@Test
179176
public void testProxiedMessageEndpointAnnotation() {
180-
TestApplicationContext context = TestUtils.createTestApplicationContext();
181-
context.registerBean(MessagingAnnotationPostProcessor.class);
177+
TestApplicationContext context = createTestApplicationContext();
182178
DirectChannel inputChannel = new DirectChannel();
183179
QueueChannel outputChannel = new QueueChannel();
184180
context.registerChannel("inputChannel", inputChannel);
@@ -195,8 +191,7 @@ public void testProxiedMessageEndpointAnnotation() {
195191

196192
@Test
197193
public void testMessageEndpointAnnotationInherited() {
198-
TestApplicationContext context = TestUtils.createTestApplicationContext();
199-
context.registerBean(MessagingAnnotationPostProcessor.class);
194+
TestApplicationContext context = createTestApplicationContext();
200195
DirectChannel inputChannel = new DirectChannel();
201196
QueueChannel outputChannel = new QueueChannel();
202197
context.registerChannel("inputChannel", inputChannel);
@@ -211,8 +206,7 @@ public void testMessageEndpointAnnotationInherited() {
211206

212207
@Test
213208
public void testMessageEndpointAnnotationInheritedWithProxy() {
214-
TestApplicationContext context = TestUtils.createTestApplicationContext();
215-
context.registerBean(MessagingAnnotationPostProcessor.class);
209+
TestApplicationContext context = createTestApplicationContext();
216210
DirectChannel inputChannel = new DirectChannel();
217211
QueueChannel outputChannel = new QueueChannel();
218212
context.registerChannel("inputChannel", inputChannel);
@@ -229,8 +223,7 @@ public void testMessageEndpointAnnotationInheritedWithProxy() {
229223

230224
@Test
231225
public void testMessageEndpointAnnotationInheritedFromInterface() {
232-
TestApplicationContext context = TestUtils.createTestApplicationContext();
233-
context.registerBean(MessagingAnnotationPostProcessor.class);
226+
TestApplicationContext context = createTestApplicationContext();
234227
DirectChannel inputChannel = new DirectChannel();
235228
QueueChannel outputChannel = new QueueChannel();
236229
context.registerChannel("inputChannel", inputChannel);
@@ -245,8 +238,7 @@ public void testMessageEndpointAnnotationInheritedFromInterface() {
245238

246239
@Test
247240
public void testMessageEndpointAnnotationInheritedFromInterfaceWithAutoCreatedChannels() {
248-
TestApplicationContext context = TestUtils.createTestApplicationContext();
249-
context.registerBean(MessagingAnnotationPostProcessor.class);
241+
TestApplicationContext context = createTestApplicationContext();
250242
DirectChannel inputChannel = new DirectChannel();
251243
QueueChannel outputChannel = new QueueChannel();
252244
context.registerChannel("inputChannel", inputChannel);
@@ -261,8 +253,7 @@ public void testMessageEndpointAnnotationInheritedFromInterfaceWithAutoCreatedCh
261253

262254
@Test
263255
public void testMessageEndpointAnnotationInheritedFromInterfaceWithProxy() {
264-
TestApplicationContext context = TestUtils.createTestApplicationContext();
265-
context.registerBean(MessagingAnnotationPostProcessor.class);
256+
TestApplicationContext context = createTestApplicationContext();
266257
DirectChannel inputChannel = new DirectChannel();
267258
QueueChannel outputChannel = new QueueChannel();
268259
context.registerChannel("inputChannel", inputChannel);
@@ -278,8 +269,7 @@ public void testMessageEndpointAnnotationInheritedFromInterfaceWithProxy() {
278269

279270
@Test
280271
public void testTransformer() {
281-
TestApplicationContext context = TestUtils.createTestApplicationContext();
282-
context.registerBean(MessagingAnnotationPostProcessor.class);
272+
TestApplicationContext context = createTestApplicationContext();
283273
DirectChannel inputChannel = new DirectChannel();
284274
context.registerChannel("inputChannel", inputChannel);
285275
QueueChannel outputChannel = new QueueChannel();
@@ -298,6 +288,12 @@ public void testTransformer() {
298288
context.close();
299289
}
300290

291+
private static TestApplicationContext createTestApplicationContext() {
292+
TestApplicationContext context = TestUtils.createTestApplicationContext();
293+
new IntegrationRegistrar().registerBeanDefinitions(mock(), context.getDefaultListableBeanFactory());
294+
return context;
295+
}
296+
301297
@MessageEndpoint
302298
public static class OutboundOnlyTestBean {
303299

spring-integration-core/src/test/java/org/springframework/integration/config/annotation/RouterAnnotationPostProcessorTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
import org.springframework.integration.annotation.Router;
2828
import org.springframework.integration.channel.DirectChannel;
2929
import org.springframework.integration.channel.QueueChannel;
30-
import org.springframework.integration.config.MessagingAnnotationPostProcessor;
30+
import org.springframework.integration.config.IntegrationRegistrar;
3131
import org.springframework.integration.test.util.TestUtils;
3232
import org.springframework.integration.test.util.TestUtils.TestApplicationContext;
3333
import org.springframework.messaging.Message;
3434
import org.springframework.messaging.support.GenericMessage;
3535

3636
import static org.assertj.core.api.Assertions.assertThat;
37+
import static org.mockito.Mockito.mock;
3738

3839
/**
3940
* @author Mark Fisher
@@ -56,7 +57,7 @@ public class RouterAnnotationPostProcessorTests {
5657

5758
@BeforeEach
5859
public void init() {
59-
this.context.registerBean(MessagingAnnotationPostProcessor.class);
60+
new IntegrationRegistrar().registerBeanDefinitions(mock(), this.context.getDefaultListableBeanFactory());
6061
context.registerChannel("input", inputChannel);
6162
context.registerChannel("output", outputChannel);
6263
context.registerChannel("routingChannel", routingChannel);

0 commit comments

Comments
 (0)