Skip to content

Commit acd78a7

Browse files
garyrussellartembilan
authored andcommitted
INT-4455: Fix NPE in Exception router
JIRA: https://jira.spring.io/browse/INT-4455 When using java config, `setChannelMapping` NPEs due to no AC. **cherry-pick to 4.3.x, and to master, removing AC check** * Polishing - PR comment * Resolve TODO in the `ErrorMessageExceptionTypeRouter`
1 parent 6dfe96d commit acd78a7

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -27,6 +27,7 @@
2727
import org.springframework.jmx.export.annotation.ManagedOperation;
2828
import org.springframework.messaging.Message;
2929
import org.springframework.messaging.MessageChannel;
30+
import org.springframework.util.Assert;
3031
import org.springframework.util.ClassUtils;
3132

3233
/**
@@ -41,6 +42,7 @@
4142
* @author Mark Fisher
4243
* @author Oleg Zhurakousky
4344
* @author Artem Bilan
45+
* @author Gary Russell
4446
*/
4547
public class ErrorMessageExceptionTypeRouter extends AbstractMappingMessageRouter {
4648

@@ -67,6 +69,7 @@ private void populateClassNameMapping(Set<String> classNames) {
6769

6870
private Class<?> resolveClassFromName(String className) {
6971
try {
72+
Assert.state(getApplicationContext() != null, "An ApplicationContext is required");
7073
return ClassUtils.forName(className, getApplicationContext().getClassLoader());
7174
}
7275
catch (ClassNotFoundException e) {
@@ -78,9 +81,11 @@ private Class<?> resolveClassFromName(String className) {
7881
@ManagedOperation
7982
public void setChannelMapping(String key, String channelName) {
8083
super.setChannelMapping(key, channelName);
81-
Map<String, Class<?>> newClassNameMappings = new ConcurrentHashMap<>(this.classNameMappings);
82-
newClassNameMappings.put(key, resolveClassFromName(key));
83-
this.classNameMappings = newClassNameMappings;
84+
if (this.initialized) {
85+
Map<String, Class<?>> newClassNameMappings = new ConcurrentHashMap<>(this.classNameMappings);
86+
newClassNameMappings.put(key, resolveClassFromName(key));
87+
this.classNameMappings = newClassNameMappings;
88+
}
8489
}
8590

8691
@Override

spring-integration-core/src/test/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouterTests.java

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -27,12 +27,15 @@
2727
import org.junit.Test;
2828

2929
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
30+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
31+
import org.springframework.context.annotation.Bean;
3032
import org.springframework.integration.MessageRejectedException;
3133
import org.springframework.integration.channel.QueueChannel;
3234
import org.springframework.integration.test.util.TestUtils;
3335
import org.springframework.messaging.Message;
3436
import org.springframework.messaging.MessageDeliveryException;
3537
import org.springframework.messaging.MessageHandlingException;
38+
import org.springframework.messaging.PollableChannel;
3639
import org.springframework.messaging.support.ErrorMessage;
3740
import org.springframework.messaging.support.GenericMessage;
3841

@@ -43,17 +46,17 @@
4346
*/
4447
public class ErrorMessageExceptionTypeRouterTests {
4548

46-
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
49+
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
4750

48-
private QueueChannel illegalArgumentChannel = new QueueChannel();
51+
private final QueueChannel illegalArgumentChannel = new QueueChannel();
4952

50-
private QueueChannel runtimeExceptionChannel = new QueueChannel();
53+
private final QueueChannel runtimeExceptionChannel = new QueueChannel();
5154

52-
private QueueChannel messageHandlingExceptionChannel = new QueueChannel();
55+
private final QueueChannel messageHandlingExceptionChannel = new QueueChannel();
5356

54-
private QueueChannel messageDeliveryExceptionChannel = new QueueChannel();
57+
private final QueueChannel messageDeliveryExceptionChannel = new QueueChannel();
5558

56-
private QueueChannel defaultChannel = new QueueChannel();
59+
private final QueueChannel defaultChannel = new QueueChannel();
5760

5861
@Before
5962
public void prepare() {
@@ -79,6 +82,7 @@ public void mostSpecificCause() {
7982
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
8083
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
8184
router.setDefaultOutputChannel(defaultChannel);
85+
router.afterPropertiesSet();
8286

8387
router.handleMessage(message);
8488

@@ -101,6 +105,7 @@ public void fallbackToNextMostSpecificCause() {
101105
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
102106
router.setChannelMapping(MessageHandlingException.class.getName(), "runtimeExceptionChannel");
103107
router.setDefaultOutputChannel(defaultChannel);
108+
router.afterPropertiesSet();
104109

105110
router.handleMessage(message);
106111

@@ -122,6 +127,7 @@ public void fallbackToErrorMessageType() {
122127
router.setApplicationContext(TestUtils.createTestApplicationContext());
123128
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
124129
router.setDefaultOutputChannel(defaultChannel);
130+
router.afterPropertiesSet();
125131

126132
router.handleMessage(message);
127133

@@ -141,6 +147,7 @@ public void fallbackToDefaultChannel() {
141147
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
142148
router.setApplicationContext(TestUtils.createTestApplicationContext());
143149
router.setDefaultOutputChannel(defaultChannel);
150+
router.afterPropertiesSet();
144151

145152
router.handleMessage(message);
146153

@@ -163,6 +170,7 @@ public void noMatchAndNoDefaultChannel() {
163170
router.setChannelMapping(MessageDeliveryException.class.getName(), "messageDeliveryExceptionChannel");
164171
router.setResolutionRequired(true);
165172
router.setBeanName("fooRouter");
173+
router.afterPropertiesSet();
166174

167175
try {
168176
router.handleMessage(message);
@@ -188,6 +196,7 @@ public void exceptionPayloadButNotErrorMessage() {
188196
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
189197
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
190198
router.setDefaultOutputChannel(defaultChannel);
199+
router.afterPropertiesSet();
191200

192201
router.handleMessage(message);
193202

@@ -210,6 +219,7 @@ public void intermediateCauseHasNoMappingButMostSpecificCauseDoes() {
210219
router.setChannelMapping(IllegalArgumentException.class.getName(), "illegalArgumentChannel");
211220
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
212221
router.setDefaultOutputChannel(defaultChannel);
222+
router.afterPropertiesSet();
213223

214224
router.handleMessage(message);
215225

@@ -229,6 +239,7 @@ public void testHierarchicalMapping() {
229239
router.setApplicationContext(TestUtils.createTestApplicationContext());
230240
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
231241
router.setDefaultOutputChannel(defaultChannel);
242+
router.afterPropertiesSet();
232243

233244
router.handleMessage(message);
234245

@@ -241,6 +252,7 @@ public void testInvalidMapping() {
241252
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
242253
router.setBeanFactory(beanFactory);
243254
router.setApplicationContext(TestUtils.createTestApplicationContext());
255+
router.afterPropertiesSet();
244256
try {
245257
router.setChannelMapping("foo", "fooChannel");
246258
fail("IllegalStateException expected");
@@ -251,4 +263,28 @@ public void testInvalidMapping() {
251263
}
252264
}
253265

266+
@Test
267+
public void testLateClassBinding() {
268+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
269+
ctx.getBean(ErrorMessageExceptionTypeRouter.class).handleMessage(new GenericMessage<>(new NullPointerException()));
270+
assertNotNull(ctx.getBean("channel", PollableChannel.class).receive(0));
271+
ctx.close();
272+
}
273+
274+
public static class Config {
275+
276+
@Bean
277+
public ErrorMessageExceptionTypeRouter errorMessageExceptionTypeRouter() {
278+
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
279+
router.setChannelMapping(NullPointerException.class.getName(), "channel");
280+
return router;
281+
}
282+
283+
@Bean
284+
public PollableChannel channel() {
285+
return new QueueChannel();
286+
}
287+
288+
}
289+
254290
}

0 commit comments

Comments
 (0)