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

# Conflicts:
#	spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java
This commit is contained in:
Gary Russell
2018-04-24 12:21:55 -04:00
committed by Artem Bilan
parent 7d350ce271
commit fa3935d1b2
2 changed files with 52 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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 @@ import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
@@ -40,6 +41,7 @@ import org.springframework.util.ClassUtils;
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Artem Bilan
* @author Gary Russell
*/
public class ErrorMessageExceptionTypeRouter extends AbstractMappingMessageRouter {
@@ -66,6 +68,7 @@ public class ErrorMessageExceptionTypeRouter extends AbstractMappingMessageRoute
private Class<?> resolveClassFromName(String className) {
try {
Assert.state(getApplicationContext() != null, "An ApplicationContext is required");
return ClassUtils.forName(className, getApplicationContext().getClassLoader());
}
catch (ClassNotFoundException e) {
@@ -77,9 +80,11 @@ public class ErrorMessageExceptionTypeRouter extends AbstractMappingMessageRoute
@ManagedOperation
public void setChannelMapping(String key, String channelName) {
super.setChannelMapping(key, channelName);
Map<String, Class<?>> newClassNameMappings = new ConcurrentHashMap<String, Class<?>>(this.classNameMappings);
newClassNameMappings.put(key, resolveClassFromName(key));
this.classNameMappings = newClassNameMappings;
if (this.initialized || getApplicationContext() != null) {
Map<String, Class<?>> newClassNameMappings = new ConcurrentHashMap<String, Class<?>>(this.classNameMappings);
newClassNameMappings.put(key, resolveClassFromName(key));
this.classNameMappings = newClassNameMappings;
}
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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,15 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.messaging.support.GenericMessage;
@@ -43,17 +46,17 @@ import org.springframework.messaging.support.GenericMessage;
*/
public class ErrorMessageExceptionTypeRouterTests {
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
private QueueChannel illegalArgumentChannel = new QueueChannel();
private final QueueChannel illegalArgumentChannel = new QueueChannel();
private QueueChannel runtimeExceptionChannel = new QueueChannel();
private final QueueChannel runtimeExceptionChannel = new QueueChannel();
private QueueChannel messageHandlingExceptionChannel = new QueueChannel();
private final QueueChannel messageHandlingExceptionChannel = new QueueChannel();
private QueueChannel messageDeliveryExceptionChannel = new QueueChannel();
private final QueueChannel messageDeliveryExceptionChannel = new QueueChannel();
private QueueChannel defaultChannel = new QueueChannel();
private final QueueChannel defaultChannel = new QueueChannel();
@Before
public void prepare() {
@@ -79,6 +82,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -101,6 +105,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
router.setChannelMapping(MessageHandlingException.class.getName(), "runtimeExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -122,6 +127,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setApplicationContext(TestUtils.createTestApplicationContext());
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -141,6 +147,7 @@ public class ErrorMessageExceptionTypeRouterTests {
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
router.setApplicationContext(TestUtils.createTestApplicationContext());
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -163,6 +170,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setChannelMapping(MessageDeliveryException.class.getName(), "messageDeliveryExceptionChannel");
router.setResolutionRequired(true);
router.setBeanName("fooRouter");
router.afterPropertiesSet();
try {
router.handleMessage(message);
@@ -188,6 +196,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setChannelMapping(RuntimeException.class.getName(), "runtimeExceptionChannel");
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -210,6 +219,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setChannelMapping(IllegalArgumentException.class.getName(), "illegalArgumentChannel");
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -229,6 +239,7 @@ public class ErrorMessageExceptionTypeRouterTests {
router.setApplicationContext(TestUtils.createTestApplicationContext());
router.setChannelMapping(MessageHandlingException.class.getName(), "messageHandlingExceptionChannel");
router.setDefaultOutputChannel(defaultChannel);
router.afterPropertiesSet();
router.handleMessage(message);
@@ -241,6 +252,7 @@ public class ErrorMessageExceptionTypeRouterTests {
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
router.setBeanFactory(beanFactory);
router.setApplicationContext(TestUtils.createTestApplicationContext());
router.afterPropertiesSet();
try {
router.setChannelMapping("foo", "fooChannel");
fail("IllegalStateException expected");
@@ -251,4 +263,28 @@ public class ErrorMessageExceptionTypeRouterTests {
}
}
@Test
public void testLateClassBinding() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(ErrorMessageExceptionTypeRouter.class).handleMessage(new GenericMessage<>(new NullPointerException()));
assertNotNull(ctx.getBean("channel", PollableChannel.class).receive(0));
ctx.close();
}
public static class Config {
@Bean
public ErrorMessageExceptionTypeRouter errorMessageExceptionTypeRouter() {
ErrorMessageExceptionTypeRouter router = new ErrorMessageExceptionTypeRouter();
router.setChannelMapping(NullPointerException.class.getName(), "channel");
return router;
}
@Bean
public PollableChannel channel() {
return new QueueChannel();
}
}
}