From aa8c14dcd221ae1bf552dc282fe5c931e9ac53e3 Mon Sep 17 00:00:00 2001 From: Ilayaperumal Gopinathan Date: Tue, 10 Jan 2017 10:39:45 +0530 Subject: [PATCH] Fix duplicate StreamListener mapping in parameterized classes - Add test - For StreamListener methods, filter out bridge methods Resolves #683 --- .../StreamListenerDuplicateMappingTests.java | 62 ++++++++++++++++--- ...amListenerAnnotationBeanPostProcessor.java | 4 +- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerDuplicateMappingTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerDuplicateMappingTests.java index 2063ab7c2..c440aa7df 100644 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerDuplicateMappingTests.java +++ b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerDuplicateMappingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -23,7 +23,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; +import org.springframework.cloud.stream.messaging.Sink; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.messaging.Message; @@ -38,27 +38,73 @@ public class StreamListenerDuplicateMappingTests { @Test @SuppressWarnings("unchecked") - public void testDuplicateMapping() throws Exception { + public void testDuplicateMapping() { + ConfigurableApplicationContext context = null; try { - ConfigurableApplicationContext context = SpringApplication.run(TestDuplicateMapping.class, - "--server.port=0"); + context = SpringApplication.run(TestDuplicateMapping.class, "--server.port=0"); fail("Exception expected on duplicate mapping"); } catch (BeanCreationException e) { assertThat(e.getCause().getMessage()).startsWith("Duplicate @StreamListener mapping"); } + finally { + if (context != null) { + context.close(); + } + } } - @EnableBinding(Processor.class) + @Test + public void testDuplicateMappingFromAbstractMethod() { + ConfigurableApplicationContext context = null; + try { + context = SpringApplication.run(TestDuplicateMappingFromAbstractMethod.class, "--server.port=0"); + } + catch (BeanCreationException e) { + String errorMessage = e.getCause().getMessage().startsWith("Duplicate @StreamListener mapping") ? + "Duplicate mapping exception is not expected" : "Test failed with exception"; + fail(errorMessage + ": " + e.getMessage()); + } + finally { + if (context != null) { + context.close(); + } + } + } + + @EnableBinding(Sink.class) @EnableAutoConfiguration public static class TestDuplicateMapping { - @StreamListener(Processor.INPUT) + @StreamListener(Sink.INPUT) public void receive(Message fooMessage) { } - @StreamListener(Processor.INPUT) + @StreamListener(Sink.INPUT) public void receiveDuplicateMapping(Message fooMessage) { } } + + @EnableBinding(Sink.class) + @EnableAutoConfiguration + public static class TestDuplicateMappingFromAbstractMethod implements GenericSink { + + @Override + @StreamListener(Sink.INPUT) + public void testMethod(TestBase msg) { + } + } + + public interface GenericSink { + void testMethod(T msg); + } + + public interface Base { + + } + + public class TestBase implements Base { + + } + } diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerAnnotationBeanPostProcessor.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerAnnotationBeanPostProcessor.java index a25b57499..cc80f3fa4 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerAnnotationBeanPostProcessor.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -108,7 +108,7 @@ public class StreamListenerAnnotationBeanPostProcessor @Override public void doWith(final Method method) throws IllegalArgumentException, IllegalAccessException { StreamListener streamListener = AnnotationUtils.findAnnotation(method, StreamListener.class); - if (streamListener != null) { + if (streamListener != null && !method.isBridge()) { Assert.isTrue(method.getAnnotation(Input.class) == null, StreamListenerErrorMessages.INPUT_AT_STREAM_LISTENER); String methodAnnotatedInboundName = streamListener.value();