diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java index d2e644b89a..076b1a682a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouter.java @@ -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> newClassNameMappings = new ConcurrentHashMap>(this.classNameMappings); - newClassNameMappings.put(key, resolveClassFromName(key)); - this.classNameMappings = newClassNameMappings; + if (this.initialized || getApplicationContext() != null) { + Map> newClassNameMappings = new ConcurrentHashMap>(this.classNameMappings); + newClassNameMappings.put(key, resolveClassFromName(key)); + this.classNameMappings = newClassNameMappings; + } } @Override diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouterTests.java index 60f6b9844c..6ad4dadcd4 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouterTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/ErrorMessageExceptionTypeRouterTests.java @@ -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(); + } + + } + }