From 488ec15907c53aab8730cacad073377fb4a759bf Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 1 Sep 2017 14:38:37 -0400 Subject: [PATCH] INT-4336: Fix NPE in IntegrationGraphServer JIRA: https://jira.spring.io/browse/INT-4336 Don't add "hidden" unreachable methods to the map in the `GatewayProxyFactoryBean`. The methods can never be executed and may not have all expected properties; they should not appear in the graph at all since they are unreachable. Also add defensive coding to the `IntegrationGraphServer` to avoid NPEs when unexpected conditions arise. # Conflicts: # spring-integration-core/src/test/java/org/springframework/integration/dsl/reactivestreams/ReactiveStreamsTests.java # spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java --- .../gateway/GatewayProxyFactoryBean.java | 2 +- .../graph/IntegrationGraphServer.java | 35 ++++++++++++------- .../gateway/GatewayProxyFactoryBeanTests.java | 22 ++++++++++++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index 035f280d17..95b00c5f32 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -344,7 +344,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint this.channelResolver = new BeanFactoryChannelResolver(beanFactory); } Class proxyInterface = this.determineServiceInterface(); - Method[] methods = ReflectionUtils.getAllDeclaredMethods(proxyInterface); + Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(proxyInterface); for (Method method : methods) { MethodInvocationGateway gateway = this.createGatewayForMethod(method); this.gatewayMap.put(method, gateway); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/graph/IntegrationGraphServer.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/graph/IntegrationGraphServer.java index 5400f8d7fc..7813fd3b8b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/graph/IntegrationGraphServer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/graph/IntegrationGraphServer.java @@ -273,21 +273,24 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat private MessageGatewayNode gatewayNode(String name, MessagingGatewaySupport gateway) { String errorChannel = gateway.getErrorChannel() != null ? gateway.getErrorChannel().toString() : null; + String requestChannel = gateway.getRequestChannel() != null ? gateway.getRequestChannel().toString() : null; return new MessageGatewayNode(this.nodeId.incrementAndGet(), name, gateway, - gateway.getRequestChannel().toString(), errorChannel); + requestChannel, errorChannel); } private MessageProducerNode producerNode(String name, MessageProducerSupport producer) { String errorChannel = producer.getErrorChannel() != null ? producer.getErrorChannel().toString() : null; + String outputChannel = producer.getOutputChannel() != null ? producer.getOutputChannel().toString() : null; return new MessageProducerNode(this.nodeId.incrementAndGet(), name, producer, - producer.getOutputChannel().toString(), errorChannel); + outputChannel, errorChannel); } private MessageSourceNode sourceNode(String name, SourcePollingChannelAdapter adapter) { String errorChannel = adapter.getDefaultErrorChannel() != null ? adapter.getDefaultErrorChannel().toString() : null; + String outputChannel = adapter.getOutputChannel() != null ? adapter.getOutputChannel().toString() : null; return new MessageSourceNode(this.nodeId.incrementAndGet(), name, adapter.getMessageSource(), - adapter.getOutputChannel().toString(), errorChannel); + outputChannel, errorChannel); } private MessageHandlerNode handlerNode(String name, IntegrationConsumer consumer) { @@ -311,8 +314,9 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat outputChannelName, null, false); } else { + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return new MessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), outputChannelName); + inputChannel, outputChannelName); } } @@ -339,8 +343,9 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat outputChannelName, errorChannel, true); } else { + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return new ErrorCapableMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), outputChannelName, errorChannel); + inputChannel, outputChannelName, errorChannel); } } @@ -356,21 +361,23 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat named.getComponentType())); } } + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return polled ? new ErrorCapableCompositeMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, errors, innerHandlers) + inputChannel, output, errors, innerHandlers) : new CompositeMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, innerHandlers); + inputChannel, output, innerHandlers); } private MessageHandlerNode discardingHandler(String name, IntegrationConsumer consumer, DiscardingMessageHandler handler, String output, String errors, boolean polled) { String discards = handler.getDiscardChannel() != null ? handler.getDiscardChannel().toString() : null; + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return polled ? new ErrorCapableDiscardingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, discards, errors) + inputChannel, output, discards, errors) : new DiscardingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, discards); + inputChannel, output, discards); } private MessageHandlerNode routingHandler(String name, IntegrationConsumer consumer, MessageHandler handler, @@ -381,11 +388,12 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat routes = new ArrayList(routes); routes.addAll(dynamicChannelNames); } + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return polled ? new ErrorCapableRoutingNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, errors, routes) + inputChannel, output, errors, routes) : new RoutingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, routes); + inputChannel, output, routes); } private MessageHandlerNode recipientListRoutingHandler(String name, IntegrationConsumer consumer, @@ -396,11 +404,12 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat for (Object recipient : recipients) { routes.add(((Recipient) recipient).getChannel().toString()); } + String inputChannel = consumer.getInputChannel() != null ? consumer.getInputChannel().toString() : null; return polled ? new ErrorCapableRoutingNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, errors, routes) + inputChannel, output, errors, routes) : new RoutingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler, - consumer.getInputChannel().toString(), output, routes); + inputChannel, output, routes); } private void reset() { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java index 4c1e203e18..c0acb47b07 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.mock; import java.lang.reflect.Method; import java.util.Collections; +import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -455,6 +456,13 @@ public class GatewayProxyFactoryBeanTests { new ClassPathXmlApplicationContext("gatewayAutowiring.xml", GatewayProxyFactoryBeanTests.class).close(); } + @Test + public void testOverriddenMethod() { + GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(InheritChild.class); + gpfb.afterPropertiesSet(); + Map gateways = gpfb.getGateways(); + assertThat(gateways.size(), equalTo(2)); + } public static void throwTestException() throws TestException { throw new TestException(); @@ -472,6 +480,20 @@ public class GatewayProxyFactoryBeanTests { String throwCheckedException(String s) throws TestException; } + interface InheritSuper { + + String overridden(String in); + + String NotOverridden(String in); + + } + + interface InheritChild extends InheritSuper { + + @Override + String overridden(String in); + + } @SuppressWarnings("serial") static class TestException extends Exception {