diff --git a/spring-cloud-stream-binder-test/src/main/java/org/springframework/cloud/stream/binder/AbstractBinderTests.java b/spring-cloud-stream-binder-test/src/main/java/org/springframework/cloud/stream/binder/AbstractBinderTests.java index c3933d00a..c96bd78f1 100644 --- a/spring-cloud-stream-binder-test/src/main/java/org/springframework/cloud/stream/binder/AbstractBinderTests.java +++ b/spring-cloud-stream-binder-test/src/main/java/org/springframework/cloud/stream/binder/AbstractBinderTests.java @@ -17,10 +17,7 @@ package org.springframework.cloud.stream.binder; import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -34,9 +31,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; -import org.springframework.cloud.stream.binder.AbstractBinderTests.Station.Readings; import org.springframework.cloud.stream.binding.MessageConverterConfigurer; -import org.springframework.cloud.stream.binding.StreamListenerMessageHandler; import org.springframework.cloud.stream.config.BindingProperties; import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.cloud.stream.converter.CompositeMessageConverterFactory; @@ -51,12 +46,8 @@ import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.PollableChannel; import org.springframework.messaging.converter.SmartMessageConverter; -import org.springframework.messaging.handler.annotation.support.PayloadMethodArgumentResolver; -import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite; -import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; import org.springframework.util.Assert; import org.springframework.util.MimeTypeUtils; -import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -424,193 +415,6 @@ public abstract class AbstractBinderTests producerBinding = binder.bindProducer( - String.format("bad%s0a", getDestinationNameDelimiter()), - moduleOutputChannel, producerBindingProperties.getProducer()); - - Binding consumerBinding = binder.bindConsumer( - String.format("bad%s0a", getDestinationNameDelimiter()), "test-1", - moduleInputChannel, consumerBindingProperties.getConsumer()); - - Station station = new Station(); - Message message = MessageBuilder.withPayload(station).build(); - moduleInputChannel.subscribe(handler); - moduleOutputChannel.send(message); - - QueueChannel replyChannel = (QueueChannel) handler.getOutputChannel(); - - Message replyMessage = replyChannel.receive(5000); - assertThat(replyMessage.getPayload() instanceof Station).isTrue(); - producerBinding.unbind(); - consumerBinding.unbind(); - } - - @SuppressWarnings("rawtypes") - @Test - public void testSendJsonReceivePojoWithStreamListener(TestInfo testInfo) throws Exception { - StreamListenerMessageHandler handler = this.buildStreamListener( - AbstractBinderTests.class, "echoStation", Station.class); - Binder binder = getBinder(); - - BindingProperties producerBindingProperties = createProducerBindingProperties( - createProducerProperties(testInfo)); - - DirectChannel moduleOutputChannel = createBindableChannel("output", - producerBindingProperties); - - BindingProperties consumerBindingProperties = createConsumerBindingProperties( - createConsumerProperties()); - - DirectChannel moduleInputChannel = createBindableChannel("input", - consumerBindingProperties); - - Binding producerBinding = binder.bindProducer( - String.format("bad%s0d", getDestinationNameDelimiter()), - moduleOutputChannel, producerBindingProperties.getProducer()); - - Binding consumerBinding = binder.bindConsumer( - String.format("bad%s0d", getDestinationNameDelimiter()), "test-4", - moduleInputChannel, consumerBindingProperties.getConsumer()); - - String value = "{\"readings\":[{\"stationid\":\"fgh\"," - + "\"customerid\":\"12345\",\"timestamp\":null}," - + "{\"stationid\":\"hjk\",\"customerid\":\"222\",\"timestamp\":null}]}"; - - Message message = MessageBuilder.withPayload(value) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) - .build(); - moduleInputChannel.subscribe(handler); - moduleOutputChannel.send(message); - - QueueChannel channel = (QueueChannel) handler.getOutputChannel(); - - Message reply = (Message) channel.receive(5000); - - assertThat(reply).isNotNull(); - assertThat(reply.getPayload() instanceof Station).isTrue(); - producerBinding.unbind(); - consumerBinding.unbind(); - } - - @SuppressWarnings("rawtypes") - @Test - public void testSendJsonReceiveJsonWithStreamListener(TestInfo testInfo) throws Exception { - StreamListenerMessageHandler handler = this.buildStreamListener( - AbstractBinderTests.class, "echoStationString", String.class); - Binder binder = getBinder(); - - BindingProperties producerBindingProperties = createProducerBindingProperties( - createProducerProperties(testInfo)); - - DirectChannel moduleOutputChannel = createBindableChannel("output", - producerBindingProperties); - - BindingProperties consumerBindingProperties = createConsumerBindingProperties( - createConsumerProperties()); - - DirectChannel moduleInputChannel = createBindableChannel("input", - consumerBindingProperties); - - Binding producerBinding = binder.bindProducer( - String.format("bad%s0e", getDestinationNameDelimiter()), - moduleOutputChannel, producerBindingProperties.getProducer()); - - Binding consumerBinding = binder.bindConsumer( - String.format("bad%s0e", getDestinationNameDelimiter()), "test-5", - moduleInputChannel, consumerBindingProperties.getConsumer()); - - String value = "{\"readings\":[{\"stationid\":\"fgh\"," - + "\"customerid\":\"12345\",\"timestamp\":null}," - + "{\"stationid\":\"hjk\",\"customerid\":\"222\",\"timestamp\":null}]}"; - - Message message = MessageBuilder.withPayload(value) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) - .build(); - moduleInputChannel.subscribe(handler); - moduleOutputChannel.send(message); - - QueueChannel channel = (QueueChannel) handler.getOutputChannel(); - - Message reply = (Message) channel.receive(5000); - - assertThat(reply).isNotNull(); - assertThat(reply.getPayload() instanceof String).isTrue(); - producerBinding.unbind(); - consumerBinding.unbind(); - } - - @SuppressWarnings("rawtypes") - @Test - public void testSendPojoReceivePojoWithStreamListener(TestInfo testInfo) throws Exception { - StreamListenerMessageHandler handler = this.buildStreamListener( - AbstractBinderTests.class, "echoStation", Station.class); - Binder binder = getBinder(); - - BindingProperties producerBindingProperties = createProducerBindingProperties( - createProducerProperties(testInfo)); - - DirectChannel moduleOutputChannel = createBindableChannel("output", - producerBindingProperties); - - BindingProperties consumerBindingProperties = createConsumerBindingProperties( - createConsumerProperties()); - - DirectChannel moduleInputChannel = createBindableChannel("input", - consumerBindingProperties); - - Binding producerBinding = binder.bindProducer( - String.format("bad%s0f", getDestinationNameDelimiter()), - moduleOutputChannel, producerBindingProperties.getProducer()); - - Binding consumerBinding = binder.bindConsumer( - String.format("bad%s0f", getDestinationNameDelimiter()), "test-6", - moduleInputChannel, consumerBindingProperties.getConsumer()); - - Readings r1 = new Readings(); - r1.setCustomerid("123"); - r1.setStationid("XYZ"); - Readings r2 = new Readings(); - r2.setCustomerid("546"); - r2.setStationid("ABC"); - Station station = new Station(); - station.setReadings(Arrays.asList(r1, r2)); - Message message = MessageBuilder.withPayload(station) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) - .build(); - moduleInputChannel.subscribe(handler); - moduleOutputChannel.send(message); - - QueueChannel channel = (QueueChannel) handler.getOutputChannel(); - - Message reply = (Message) channel.receive(5000); - - assertThat(reply).isNotNull(); - assertThat(reply.getPayload() instanceof Station).isTrue(); - producerBinding.unbind(); - consumerBinding.unbind(); - } - @SuppressWarnings("unused") // it is used via reflection private Station echoStation(Station station) { return station; @@ -621,32 +425,6 @@ public abstract class AbstractBinderTests handlerClass, - String handlerMethodName, Class... parameters) throws Exception { - String channelName = "reply_" + System.nanoTime(); - - this.applicationContext.getBeanFactory().registerSingleton(channelName, new QueueChannel()); - - Method m = ReflectionUtils.findMethod(handlerClass, handlerMethodName, - parameters); - InvocableHandlerMethod method = new InvocableHandlerMethod(this, m); - HandlerMethodArgumentResolverComposite resolver = new HandlerMethodArgumentResolverComposite(); - CompositeMessageConverterFactory factory = new CompositeMessageConverterFactory(); - resolver.addResolver(new PayloadMethodArgumentResolver( - factory.getMessageConverterForAllRegistered())); - method.setMessageMethodArgumentResolvers(resolver); - Constructor c = ReflectionUtils.accessibleConstructor( - StreamListenerMessageHandler.class, InvocableHandlerMethod.class, - boolean.class, String[].class); - StreamListenerMessageHandler handler = (StreamListenerMessageHandler) c - .newInstance(method, false, new String[] {}); - handler.setOutputChannelName(channelName); - handler.setBeanFactory(this.applicationContext); - handler.afterPropertiesSet(); -// context.refresh(); - return handler; - } - public static class Station { List readings = new ArrayList<>(); diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotatedMethodArgumentsTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotatedMethodArgumentsTests.java deleted file mode 100644 index ad3ed5df4..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotatedMethodArgumentsTests.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; - -import jakarta.validation.Valid; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -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.integration.support.MessageBuilder; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.messaging.handler.annotation.Headers; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException; -import org.springframework.util.MimeType; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Oleg Zhurakousky - * @author Artem Bilan - */ -public class StreamListenerAnnotatedMethodArgumentsTests { - - @BeforeClass - public static void init() { - Locale.setDefault(Locale.US); - } - - @Test - @SuppressWarnings("unchecked") - public void testAnnotatedArguments() { - ConfigurableApplicationContext context = SpringApplication - .run(TestPojoWithAnnotatedArguments.class, "--server.port=0"); - - TestPojoWithAnnotatedArguments testPojoWithAnnotatedArguments = context - .getBean(TestPojoWithAnnotatedArguments.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", MimeType.valueOf("application/json")) - .setHeader("testHeader", "testValue").build()); - assertThat(testPojoWithAnnotatedArguments.receivedArguments).hasSize(3); - assertThat(testPojoWithAnnotatedArguments.receivedArguments.get(0)) - .isInstanceOf(StreamListenerTestUtils.FooPojo.class); - assertThat(testPojoWithAnnotatedArguments.receivedArguments.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - assertThat(testPojoWithAnnotatedArguments.receivedArguments.get(1)) - .isInstanceOf(Map.class); - assertThat((Map) testPojoWithAnnotatedArguments.receivedArguments - .get(1)).containsEntry(MessageHeaders.CONTENT_TYPE, - MimeType.valueOf("application/json")); - assertThat((Map) testPojoWithAnnotatedArguments.receivedArguments - .get(1)).containsEntry("testHeader", "testValue"); - assertThat(testPojoWithAnnotatedArguments.receivedArguments.get(2)) - .isEqualTo("application/json"); - context.close(); - } - - @Test - public void testInputAnnotationAtMethodParameter() { - try { - SpringApplication.run(TestPojoWithInvalidInputAnnotatedArgument.class, - "--server.port=0"); - fail("Exception expected: " + INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - @Test - public void testValidAnnotationAtMethodParameterWithPojoThatPassesValidation() { - ConfigurableApplicationContext context = SpringApplication.run( - TestPojoWithValidAnnotationThatPassesValidation.class, "--server.port=0"); - - TestPojoWithValidAnnotationThatPassesValidation testPojoWithValidAnnotationThatPassesValidation = context - .getBean(TestPojoWithValidAnnotationThatPassesValidation.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"" + id + "\"}") - .setHeader("contentType", MimeType.valueOf("application/json")).build()); - assertThat( - testPojoWithValidAnnotationThatPassesValidation.receivedArguments.get(0)) - .hasFieldOrPropertyWithValue("foo", id); - context.close(); - } - - @Test - @Ignore - public void testValidAnnotationAtMethodParameterWithPojoThatFailsValidation() { - ConfigurableApplicationContext context = SpringApplication.run( - TestPojoWithValidAnnotationThatPassesValidation.class, "--server.port=0"); - - Sink sink = context.getBean(Sink.class); - try { - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"\"}") - .setHeader("contentType", MimeType.valueOf("application/json")) - .build()); - fail("Exception expected: MethodArgumentNotValidException!"); - } - catch (MethodArgumentNotValidException e) { - assertThat(e.getMessage()).contains( - "default message [foo]]; default message [must not be blank]]"); - } - context.close(); - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithAnnotatedArguments { - - List receivedArguments = new ArrayList<>(); - - @StreamListener(Processor.INPUT) - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo, - @Headers Map headers, - @Header(MessageHeaders.CONTENT_TYPE) String contentType) { - this.receivedArguments.add(fooPojo); - this.receivedArguments.add(headers); - this.receivedArguments.add(contentType); - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithInvalidInputAnnotatedArgument { - - List receivedArguments = new ArrayList<>(); - - @StreamListener - public void receive( - @Input(Processor.INPUT) @Payload StreamListenerTestUtils.FooPojo fooPojo, - @Headers Map headers, - @Header(MessageHeaders.CONTENT_TYPE) String contentType) { - this.receivedArguments.add(fooPojo); - this.receivedArguments.add(headers); - this.receivedArguments.add(contentType); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithValidAnnotationThatPassesValidation { - - List receivedArguments = new ArrayList<>(); - - @StreamListener(Processor.INPUT) - public void receive( - @Valid StreamListenerTestUtils.PojoWithValidation pojoWithValidation) { - this.receivedArguments.add(pojoWithValidation); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotationBeanPostProcessorOverrideTest.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotationBeanPostProcessorOverrideTest.java deleted file mode 100644 index ba0e89ac5..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAnnotationBeanPostProcessorOverrideTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.junit.Ignore; -import org.junit.Test; - -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.binding.StreamListenerAnnotationBeanPostProcessor; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.handler.annotation.Payload; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.cloud.stream.config.BindingServiceConfiguration.STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME; - -/** - * @author Marius Bogoevici - */ -public class StreamListenerAnnotationBeanPostProcessorOverrideTest { - - @Test - @SuppressWarnings("unchecked") - @Ignore - public void testOverrideStreamListenerAnnotationBeanPostProcessor() throws Exception { - ConfigurableApplicationContext context = SpringApplication - .run(TestPojoWithAnnotatedArguments.class, "--server.port=0"); - - TestPojoWithAnnotatedArguments testPojoWithAnnotatedArguments = context - .getBean(TestPojoWithAnnotatedArguments.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "foo").build()); - sink.input().send(MessageBuilder.withPayload("{\"bar\":\"foofoo" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "bar").build()); - assertThat(testPojoWithAnnotatedArguments.receivedFoo).hasSize(1); - assertThat(testPojoWithAnnotatedArguments.receivedFoo.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - context.close(); - } - - @Configuration - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithAnnotatedArguments { - - List receivedFoo = new ArrayList<>(); - - /** - * Overrides the default {@link StreamListenerAnnotationBeanPostProcessor}. - */ - @Bean(name = STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME) - public static StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor() { - return new StreamListenerAnnotationBeanPostProcessor() { - @Override - protected StreamListener postProcessAnnotation( - StreamListener originalAnnotation, Method annotatedMethod) { - Map attributes = new HashMap<>( - AnnotationUtils.getAnnotationAttributes(originalAnnotation)); - attributes.put("condition", - "headers['type']=='" + originalAnnotation.condition() + "'"); - return AnnotationUtils.synthesizeAnnotation(attributes, - StreamListener.class, annotatedMethod); - } - }; - } - - @StreamListener(value = Sink.INPUT, condition = "foo") - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedFoo.add(fooPojo); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAsMetaAnnotationTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAsMetaAnnotationTests.java deleted file mode 100644 index a1edb0922..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerAsMetaAnnotationTests.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2017-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.junit.Ignore; -import org.junit.Test; - -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.Sink; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.annotation.AliasFor; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.Payload; - -import static org.assertj.core.api.Assertions.assertThat; - -@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@MessageMapping -@Documented -@StreamListener -@interface EventHandler { - - /** - * The name of the binding target (e.g. channel) that the method subscribes to. - * @return the name of the binding target. - */ - @AliasFor(annotation = StreamListener.class, attribute = "target") - String value() default ""; - - /** - * The name of the binding target (e.g. channel) that the method subscribes to. - * @return the name of the binding target. - */ - @AliasFor(annotation = StreamListener.class, attribute = "target") - String target() default ""; - - /** - * A condition that must be met by all items that are dispatched to this method. - * @return a SpEL expression that must evaluate to a {@code boolean} value. - */ - @AliasFor(annotation = StreamListener.class, attribute = "condition") - String condition() default ""; - -} - -/** - * @author David Turanski - */ -public class StreamListenerAsMetaAnnotationTests { - - @Test - @Ignore - public void testCustomAnnotation() { - ConfigurableApplicationContext context = SpringApplication - .run(TestPojoWithCustomAnnotatedArguments.class, "--server.port=0"); - - TestPojoWithCustomAnnotatedArguments testPojoWithAnnotatedArguments = context - .getBean(TestPojoWithCustomAnnotatedArguments.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "foo").build()); - assertThat(testPojoWithAnnotatedArguments.receivedFoo).hasSize(1); - assertThat(testPojoWithAnnotatedArguments.receivedFoo.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - context.close(); - } - - @Test - @Ignore - public void testAnnotation() { - ConfigurableApplicationContext context = SpringApplication - .run(TestPojoWithAnnotatedArguments.class, "--server.port=0"); - - TestPojoWithAnnotatedArguments testPojoWithAnnotatedArguments = context - .getBean(TestPojoWithAnnotatedArguments.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "foo").build()); - assertThat(testPojoWithAnnotatedArguments.receivedFoo).hasSize(1); - assertThat(testPojoWithAnnotatedArguments.receivedFoo.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - context.close(); - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithCustomAnnotatedArguments { - - List receivedFoo = new ArrayList<>(); - - List receivedBar = new ArrayList<>(); - - @EventHandler(value = Sink.INPUT, condition = "headers['type']=='foo'") - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedFoo.add(fooPojo); - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithAnnotatedArguments { - - List receivedFoo = new ArrayList<>(); - - List receivedBar = new ArrayList<>(); - - @StreamListener(value = Sink.INPUT, condition = "headers['type']=='foo'") - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedFoo.add(fooPojo); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerContentTypeConversionTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerContentTypeConversionTests.java deleted file mode 100644 index a827552c3..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerContentTypeConversionTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - -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.Sink; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - */ -public class StreamListenerContentTypeConversionTests { - - @Test - public void testContentTypeConversion() throws Exception { - ConfigurableApplicationContext context = SpringApplication - .run(TestSinkWithContentTypeConversion.class, "--server.port=0"); - @SuppressWarnings("unchecked") - TestSinkWithContentTypeConversion testSink = context - .getBean(TestSinkWithContentTypeConversion.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - assertThat(testSink.latch.await(10, TimeUnit.SECONDS)); - assertThat(testSink.receivedArguments).hasSize(1); - assertThat(testSink.receivedArguments.get(0)).hasFieldOrPropertyWithValue("foo", - "barbar" + id); - context.close(); - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestSinkWithContentTypeConversion { - - List receivedArguments = new ArrayList<>(); - - CountDownLatch latch = new CountDownLatch(1); - - @StreamListener(Sink.INPUT) - public void receive(StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedArguments.add(fooPojo); - this.latch.countDown(); - } - - } - -} 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 deleted file mode 100644 index c5cb84694..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerDuplicateMappingTests.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import org.junit.Test; - -import org.springframework.beans.factory.BeanCreationException; -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.binding.StreamListenerErrorMessages; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.SendTo; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - */ -public class StreamListenerDuplicateMappingTests { - - @Test - @SuppressWarnings("unchecked") - public void testMultipleMappingsWithReturnValue() { - ConfigurableApplicationContext context = null; - try { - context = SpringApplication.run(TestMultipleMappingsWithReturnValue.class, - "--server.port=0"); - fail("Exception expected on duplicate mapping"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).startsWith( - StreamListenerErrorMessages.MULTIPLE_VALUE_RETURNING_METHODS); - } - finally { - if (context != null) { - context.close(); - } - } - } - - @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(); - } - } - } - - public interface GenericSink { - - void testMethod(T msg); - - } - - public interface Base { - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestMultipleMappingsWithReturnValue { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receive(Message fooMessage) { - return null; - } - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receiveDuplicateMapping(Message fooMessage) { - return null; - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestDuplicateMappingFromAbstractMethod - implements GenericSink { - - @Override - @StreamListener(Sink.INPUT) - public void testMethod(TestBase msg) { - } - - } - - public class TestBase implements Base { - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerBeanTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerBeanTests.java deleted file mode 100644 index 160c9aefd..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerBeanTests.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -@RunWith(Parameterized.class) -public class StreamListenerHandlerBeanTests { - - private Class configClass; - - public StreamListenerHandlerBeanTests(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList(TestHandlerBeanWithSendTo.class, TestHandlerBean2.class); - } - - @Test - @SuppressWarnings("unchecked") - public void testHandlerBean() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run(this.configClass, - "--spring.cloud.stream.bindings.output.contentType=application/json", - "--server.port=0"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - HandlerBean handlerBean = context.getBean(HandlerBean.class); - Assertions.assertThat(handlerBean.receivedPojos).hasSize(1); - Assertions.assertThat(handlerBean.receivedPojos.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - assertThat(message).isNotNull(); - assertThat(message.getPayload()).isEqualTo("{\"bar\":\"barbar" + id + "\"}"); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_JSON)); - context.close(); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestHandlerBeanWithSendTo { - - @Bean - public HandlerBeanWithSendTo handlerBean() { - return new HandlerBeanWithSendTo(); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestHandlerBean2 { - - @Bean - public HandlerBeanWithOutput handlerBean() { - return new HandlerBeanWithOutput(); - } - - } - - public static class HandlerBeanWithSendTo extends HandlerBean { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive( - StreamListenerTestUtils.FooPojo fooMessage) { - this.receivedPojos.add(fooMessage); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooMessage.getFoo()); - return barPojo; - } - - } - - public static class HandlerBeanWithOutput extends HandlerBean { - - @StreamListener(Processor.INPUT) - @Output(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive( - StreamListenerTestUtils.FooPojo fooMessage) { - this.receivedPojos.add(fooMessage); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooMessage.getFoo()); - return barPojo; - } - - } - - public static class HandlerBean { - - List receivedPojos = new ArrayList<>(); - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerMethodTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerMethodTests.java deleted file mode 100644 index 0be6c2147..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerHandlerMethodTests.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binding.StreamListenerErrorMessages; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.annotation.Router; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.integration.support.DefaultMessageBuilderFactory; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.util.Assert; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INPUT_AT_STREAM_LISTENER; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_INBOUND_NAME; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_OUTBOUND_NAME; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_OUTPUT_VALUES; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.NO_INPUT_DESTINATION; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.RETURN_TYPE_MULTIPLE_OUTBOUND_SPECIFIED; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.RETURN_TYPE_NO_OUTBOUND_SPECIFIED; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Gary Russell - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -public class StreamListenerHandlerMethodTests { - - @Test - public void testInvalidInputOnMethod() throws Exception { - try { - SpringApplication.run(TestInvalidInputOnMethod.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected: " + INPUT_AT_STREAM_LISTENER); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INPUT_AT_STREAM_LISTENER); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testMethodWithObjectAsMethodArgument() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestMethodWithObjectAsMethodArgument.class, "--server.port=0", - "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.cloud.stream.bindings.output.contentType=text/plain"); - Processor processor = context.getBean(Processor.class); - final String testMessage = "testing"; - processor.input().send(MessageBuilder.withPayload(testMessage).build()); - MessageCollector messageCollector = context.getBean(MessageCollector.class); - Message result = (Message) messageCollector - .forChannel(processor.output()).poll(1000, TimeUnit.MILLISECONDS); - assertThat(result).isNotNull(); - assertThat(result.getPayload()).isEqualTo(testMessage.toUpperCase()); - context.close(); - } - - @SuppressWarnings("unchecked") - @Test - /** - * @since 2.0 : This test is an example of the new behavior of 2.0 when it comes to - * contentType handling. The default contentType being JSON in order to be able to - * check a message without quotes the user needs to set the input/output contentType - * accordingly Also, received messages are always of Message now. - */ - public void testMethodHeadersPropagatged() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestMethodHeadersPropagated.class, "--server.port=0", - "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.cloud.stream.bindings.output.contentType=text/plain"); - Processor processor = context.getBean(Processor.class); - final String testMessage = "testing"; - processor.input().send( - MessageBuilder.withPayload(testMessage).setHeader("foo", "bar").build()); - MessageCollector messageCollector = context.getBean(MessageCollector.class); - Message result = (Message) messageCollector - .forChannel(processor.output()).poll(1000, TimeUnit.MILLISECONDS); - assertThat(result).isNotNull(); - assertThat(result.getPayload()).isEqualTo(testMessage.toUpperCase()); - assertThat(result.getHeaders().get("foo")).isEqualTo("bar"); - context.close(); - } - - @SuppressWarnings("unchecked") - @Test - @Disabled - public void testMethodHeadersNotPropagatged() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestMethodHeadersNotPropagated.class, "--server.port=0", - "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.cloud.stream.bindings.output.contentType=text/plain"); - Processor processor = context.getBean(Processor.class); - final String testMessage = "testing"; - processor.input().send( - MessageBuilder.withPayload(testMessage).setHeader("foo", "bar").build()); - MessageCollector messageCollector = context.getBean(MessageCollector.class); - Message result = (Message) messageCollector - .forChannel(processor.output()).poll(1000, TimeUnit.MILLISECONDS); - assertThat(result).isNotNull(); - assertThat(result.getPayload()).isEqualTo(testMessage.toUpperCase()); - assertThat(result.getHeaders().get("foo")).isNull(); - context.close(); - } - - // TODO: Handle dynamic destinations and contentType - @SuppressWarnings("unchecked") - public void testStreamListenerMethodWithTargetBeanFromOutside() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestStreamListenerMethodWithTargetBeanFromOutside.class, - "--server.port=0", "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.cloud.stream.bindings.output.contentType=text/plain"); - Sink sink = context.getBean(Sink.class); - final String testMessageToSend = "testing"; - sink.input().send(MessageBuilder.withPayload(testMessageToSend).build()); - DirectChannel directChannel = (DirectChannel) context - .getBean(testMessageToSend.toUpperCase(), MessageChannel.class); - MessageCollector messageCollector = context.getBean(MessageCollector.class); - Message result = (Message) messageCollector - .forChannel(directChannel).poll(1000, TimeUnit.MILLISECONDS); - sink.input().send(MessageBuilder.withPayload(testMessageToSend).build()); - assertThat(result).isNotNull(); - assertThat(result.getPayload()).isEqualTo(testMessageToSend.toUpperCase()); - context.close(); - } - - @Test - public void testInvalidReturnTypeWithSendToAndOutput() throws Exception { - try { - SpringApplication.run(TestReturnTypeWithMultipleOutput.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected: " + RETURN_TYPE_MULTIPLE_OUTBOUND_SPECIFIED); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(RETURN_TYPE_MULTIPLE_OUTBOUND_SPECIFIED); - } - } - - @Test - public void testInvalidReturnTypeWithNoOutput() throws Exception { - try { - SpringApplication.run(TestInvalidReturnTypeWithNoOutput.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected: " + RETURN_TYPE_NO_OUTBOUND_SPECIFIED); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(RETURN_TYPE_NO_OUTBOUND_SPECIFIED); - } - } - - @Test - public void testInvalidInputAnnotationWithNoValue() throws Exception { - try { - SpringApplication.run(TestInvalidInputAnnotationWithNoValue.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected: " + INVALID_INBOUND_NAME); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INVALID_INBOUND_NAME); - } - } - - @Test - public void testInvalidOutputAnnotationWithNoValue() throws Exception { - try { - SpringApplication.run(TestInvalidOutputAnnotationWithNoValue.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected: " + INVALID_OUTBOUND_NAME); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INVALID_OUTBOUND_NAME); - } - } - - @Test - public void testMethodInvalidInboundName() throws Exception { - try { - SpringApplication.run(TestMethodInvalidInboundName.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected on using invalid inbound name"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains( - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - @Test - public void testMethodInvalidOutboundName() throws Exception { - try { - SpringApplication.run(TestMethodInvalidOutboundName.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected on using invalid outbound name"); - } - catch (NoSuchBeanDefinitionException e) { - assertThat(e.getMessage()).contains("invalid"); - } - } - - @Test - public void testAmbiguousMethodArguments1() throws Exception { - try { - SpringApplication.run(TestAmbiguousMethodArguments1.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected: " + AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()) - .contains(AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS); - } - } - - @Test - public void testAmbiguousMethodArguments2() throws Exception { - try { - SpringApplication.run(TestAmbiguousMethodArguments2.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected:" + AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()) - .contains(AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS); - } - } - - @Test - public void testMethodWithInputAsMethodAndParameter() throws Exception { - try { - SpringApplication.run(TestMethodWithInputAsMethodAndParameter.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected: " + INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - @Test - public void testMethodWithOutputAsMethodAndParameter() throws Exception { - try { - SpringApplication.run(TestMethodWithOutputAsMethodAndParameter.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected:" + INVALID_OUTPUT_VALUES); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).startsWith(INVALID_OUTPUT_VALUES); - } - } - - @Test - public void testMethodWithoutInput() throws Exception { - try { - SpringApplication.run(TestMethodWithoutInput.class, "--server.port=0", - "--spring.jmx.enabled=false"); - fail("Exception expected when inbound target is not set"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(NO_INPUT_DESTINATION); - } - } - - @Test - public void testMethodWithMultipleInputParameters() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestMethodWithMultipleInputParameters.class, "--server.port=0", - "--spring.jmx.enabled=false"); - Processor processor = context.getBean(Processor.class); - StreamListenerTestUtils.FooInboundChannel1 inboundChannel2 = context - .getBean(StreamListenerTestUtils.FooInboundChannel1.class); - final CountDownLatch latch = new CountDownLatch(2); - ((SubscribableChannel) processor.output()).subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - Assert.isTrue( - message.getPayload().equals("footesting") - || message.getPayload().equals("BARTESTING"), - "Assert failed"); - latch.countDown(); - } - }); - processor.input().send(MessageBuilder.withPayload("{\"foo\":\"fooTESTing\"}") - .setHeader("contentType", "application/json").build()); - inboundChannel2.input() - .send(MessageBuilder.withPayload("{\"bar\":\"bartestING\"}") - .setHeader("contentType", "application/json").build()); - assertThat(latch.await(1, TimeUnit.SECONDS)); - context.close(); - } - - @Test - public void testMethodWithMultipleOutputParameters() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestMethodWithMultipleOutputParameters.class, "--server.port=0", - "--spring.jmx.enabled=false"); - Processor processor = context.getBean(Processor.class); - StreamListenerTestUtils.FooOutboundChannel1 source2 = context - .getBean(StreamListenerTestUtils.FooOutboundChannel1.class); - final CountDownLatch latch = new CountDownLatch(2); - ((SubscribableChannel) processor.output()).subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - Assert.isTrue(message.getPayload().equals("testing"), "Assert failed"); - Assert.isTrue(message.getHeaders().get("output").equals("output2"), - "Assert failed"); - latch.countDown(); - } - }); - ((SubscribableChannel) source2.output()).subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - Assert.isTrue(message.getPayload().equals("TESTING"), "Assert failed"); - Assert.isTrue(message.getHeaders().get("output").equals("output1"), - "Assert failed"); - latch.countDown(); - } - }); - processor.input().send(MessageBuilder.withPayload("testING") - .setHeader("output", "output1").build()); - processor.input().send(MessageBuilder.withPayload("TESTing") - .setHeader("output", "output2").build()); - assertThat(latch.await(1, TimeUnit.SECONDS)); - context.close(); - } - - @EnableBinding({ Processor.class, StreamListenerTestUtils.FooOutboundChannel1.class }) - @EnableAutoConfiguration - public static class TestMethodWithMultipleOutputParameters { - - @StreamListener - public void receive(@Input(Processor.INPUT) SubscribableChannel input, - @Output(Processor.OUTPUT) final MessageChannel output1, - @Output(StreamListenerTestUtils.FooOutboundChannel1.OUTPUT) final MessageChannel output2) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - if (message.getHeaders().get("output").equals("output1")) { - output1.send(org.springframework.messaging.support.MessageBuilder - .withPayload( - message.getPayload().toString().toUpperCase()) - .build()); - } - else if (message.getHeaders().get("output").equals("output2")) { - output2.send(org.springframework.messaging.support.MessageBuilder - .withPayload( - message.getPayload().toString().toLowerCase()) - .build()); - } - } - }); - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestMethodWithoutInput { - - @StreamListener - public void receive(StreamListenerTestUtils.FooPojo fooPojo) { - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestMethodWithObjectAsMethodArgument { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receive(Object received) { - return received.toString().toUpperCase(); - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestMethodHeadersPropagated { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receive(String received) { - return received.toUpperCase(); - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestMethodHeadersNotPropagated { - - @StreamListener(value = Processor.INPUT, copyHeaders = "${foo.bar:false}") - @SendTo(Processor.OUTPUT) - public String receive(String received) { - return received.toUpperCase(); - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestStreamListenerMethodWithTargetBeanFromOutside { - - private static final String ROUTER_QUEUE = "routeInstruction"; - - @StreamListener(Sink.INPUT) - @SendTo(ROUTER_QUEUE) - public Message convertMessageBody(Message message) { - return new DefaultMessageBuilderFactory() - .withPayload(message.getPayload().toUpperCase()).build(); - } - - @Router(inputChannel = ROUTER_QUEUE) - public String route(String message) { - return message.toUpperCase(); - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestInvalidInputOnMethod { - - @StreamListener - @Input(Sink.INPUT) - public void receive(StreamListenerTestUtils.FooPojo fooPojo) { - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestAmbiguousMethodArguments1 { - - @StreamListener(Processor.INPUT) - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo, - String value) { - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestAmbiguousMethodArguments2 { - - @StreamListener(Processor.INPUT) - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo, - @Payload StreamListenerTestUtils.BarPojo barPojo) { - } - - } - - @EnableBinding({ Processor.class, StreamListenerTestUtils.FooOutboundChannel1.class }) - @EnableAutoConfiguration - public static class TestReturnTypeWithMultipleOutput { - - @StreamListener - public String receive(@Input(Processor.INPUT) SubscribableChannel input1, - @Output(Processor.OUTPUT) MessageChannel output1, - @Output(StreamListenerTestUtils.FooOutboundChannel1.OUTPUT) MessageChannel output2) { - return "foo"; - } - - } - - @EnableBinding({ Processor.class, StreamListenerTestUtils.FooOutboundChannel1.class }) - @EnableAutoConfiguration - public static class TestInvalidReturnTypeWithNoOutput { - - @StreamListener - public String receive(@Input(Processor.INPUT) SubscribableChannel input1) { - return "foo"; - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestInvalidInputAnnotationWithNoValue { - - @StreamListener - public void receive(@Input SubscribableChannel input) { - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestInvalidOutputAnnotationWithNoValue { - - @StreamListener - public void receive(@Input(Processor.OUTPUT) SubscribableChannel input, - @Output MessageChannel output) { - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestMethodInvalidInboundName { - - @StreamListener - public void receive(@Input("invalid") SubscribableChannel input) { - } - - } - - @EnableBinding({ Processor.class }) - @EnableAutoConfiguration - public static class TestMethodInvalidOutboundName { - - @StreamListener - public void receive(@Input(Processor.INPUT) SubscribableChannel input, - @Output("invalid") MessageChannel output) { - } - - } - - @EnableBinding({ Sink.class }) - @EnableAutoConfiguration - public static class TestMethodWithInputAsMethodAndParameter { - - @StreamListener - public void receive(@Input(Sink.INPUT) StreamListenerTestUtils.FooPojo fooPojo) { - } - - } - - @EnableBinding({ Processor.class, StreamListenerTestUtils.FooOutboundChannel1.class }) - @EnableAutoConfiguration - public static class TestMethodWithOutputAsMethodAndParameter { - - @StreamListener - @Output(StreamListenerTestUtils.FooOutboundChannel1.OUTPUT) - public void receive(@Input(Processor.INPUT) SubscribableChannel input, - @Output(Processor.OUTPUT) final MessageChannel output1) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output1.send(org.springframework.messaging.support.MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - - @EnableBinding({ Processor.class, StreamListenerTestUtils.FooInboundChannel1.class }) - @EnableAutoConfiguration - public static class TestMethodWithMultipleInputParameters { - - @StreamListener - public void receive(@Input(Processor.INPUT) SubscribableChannel input1, - @Input(StreamListenerTestUtils.FooInboundChannel1.INPUT) SubscribableChannel input2, - final @Output(Processor.OUTPUT) MessageChannel output) { - input1.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(org.springframework.messaging.support.MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - input2.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(org.springframework.messaging.support.MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMessageArgumentTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMessageArgumentTests.java deleted file mode 100644 index 028e2222e..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMessageArgumentTests.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.SendTo; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -@RunWith(Parameterized.class) -public class StreamListenerMessageArgumentTests { - - private Class configClass; - - public StreamListenerMessageArgumentTests(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList(new Class[] { TestPojoWithMessageArgument1.class, - TestPojoWithMessageArgument2.class }); - } - - @Test - @SuppressWarnings("unchecked") - public void testMessageArgument() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run(this.configClass, - "--server.port=0", - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input().send(MessageBuilder.withPayload("barbar" + id) - .setHeader("contentType", "text/plain").build()); - TestPojoWithMessageArgument testPojoWithMessageArgument = context - .getBean(TestPojoWithMessageArgument.class); - assertThat(testPojoWithMessageArgument.receivedMessages).hasSize(1); - assertThat(testPojoWithMessageArgument.receivedMessages.get(0).getPayload()) - .isEqualTo("barbar" + id); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - assertThat(message).isNotNull(); - assertThat(message.getPayload()).contains("barbar" + id); - context.close(); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMessageArgument1 extends TestPojoWithMessageArgument { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive(Message fooMessage) { - this.receivedMessages.add(fooMessage); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooMessage.getPayload()); - return barPojo; - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMessageArgument2 extends TestPojoWithMessageArgument { - - @StreamListener(Processor.INPUT) - @Output(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive(Message fooMessage) { - this.receivedMessages.add(fooMessage); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooMessage.getPayload()); - return barPojo; - } - - } - - public static class TestPojoWithMessageArgument { - - List> receivedMessages = new ArrayList<>(); - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodRegisteredOnlyOnceTest.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodRegisteredOnlyOnceTest.java deleted file mode 100644 index 7b475d835..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodRegisteredOnlyOnceTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.mockito.Mockito.verify; - -/** - * See issue https://github.com/spring-cloud/spring-cloud-stream/issues/1080 - * - * StreamListener method called twice when using @SpyBean - * - * @author Soby Chacko - */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest -public class StreamListenerMethodRegisteredOnlyOnceTest { - - @Autowired - private SomeSink sink; - - @SpyBean - private SomeHandler handler; - - @Test - public void should_handleSomeMessage() { - this.sink.channel().send(new GenericMessage<>("Payload")); - verify(this.handler).handleMessage(); // should only be invoked once. - } - - public interface SomeSink { - - @Input(Sink.INPUT) - SubscribableChannel channel(); - - } - - @EnableBinding(SomeSink.class) - @EnableAutoConfiguration - public static class SomeHandler { - - @StreamListener(Sink.INPUT) - public void handleMessage() { - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodReturnWithConversionTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodReturnWithConversionTests.java deleted file mode 100644 index 5c6fe2eea..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodReturnWithConversionTests.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - * - */ -@RunWith(StreamListenerMethodReturnWithConversionTests.class) -@Suite.SuiteClasses({ - StreamListenerMethodReturnWithConversionTests.TestReturnConversion.class, - StreamListenerMethodReturnWithConversionTests.TestReturnNoConversion.class }) -public class StreamListenerMethodReturnWithConversionTests extends Suite { - - public StreamListenerMethodReturnWithConversionTests(Class klass, - RunnerBuilder builder) throws InitializationError { - super(klass, builder); - } - - @RunWith(Parameterized.class) - public static class TestReturnConversion { - - private Class configClass; - - public TestReturnConversion(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList(new Class[] { TestPojoWithMimeType1.class, - TestPojoWithMimeType2.class }); - } - - @Test - @SuppressWarnings("unchecked") - public void testReturnConversion() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - this.configClass, - "--spring.cloud.stream.bindings.output.contentType=application/json", - "--server.port=0", "--spring.jmx.enabled=false"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - TestPojoWithMimeType testPojoWithMimeType = context - .getBean(TestPojoWithMimeType.class); - Assertions.assertThat(testPojoWithMimeType.receivedPojos).hasSize(1); - Assertions.assertThat(testPojoWithMimeType.receivedPojos.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - assertThat(message).isNotNull(); - assertThat(new String(message.getPayload())) - .isEqualTo("{\"bar\":\"barbar" + id + "\"}"); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_JSON)); - context.close(); - } - - } - - @RunWith(Parameterized.class) - public static class TestReturnNoConversion { - - private Class configClass; - - private ObjectMapper mapper = new ObjectMapper(); - - public TestReturnNoConversion(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList(new Class[] { TestPojoWithMimeType1.class, - TestPojoWithMimeType2.class }); - } - - @Test - @SuppressWarnings("unchecked") - public void testReturnNoConversion() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - this.configClass, "--server.port=0", "--spring.jmx.enabled=false"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - TestPojoWithMimeType testPojoWithMimeType = context - .getBean(TestPojoWithMimeType.class); - Assertions.assertThat(testPojoWithMimeType.receivedPojos).hasSize(1); - Assertions.assertThat(testPojoWithMimeType.receivedPojos.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - assertThat(message).isNotNull(); - StreamListenerTestUtils.BarPojo barPojo = this.mapper.readValue( - message.getPayload(), StreamListenerTestUtils.BarPojo.class); - assertThat(barPojo.getBar()).isEqualTo("barbar" + id); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE, - MimeType.class) != null); - context.close(); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMimeType1 extends TestPojoWithMimeType { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive( - StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooPojo.getFoo()); - return barPojo; - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMimeType2 extends TestPojoWithMimeType { - - @StreamListener(Processor.INPUT) - @Output(Processor.OUTPUT) - public StreamListenerTestUtils.BarPojo receive( - StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooPojo.getFoo()); - return barPojo; - } - - } - - public static class TestPojoWithMimeType { - - List receivedPojos = new ArrayList<>(); - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodSetupOrchestratorTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodSetupOrchestratorTests.java deleted file mode 100644 index ba89ee697..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodSetupOrchestratorTests.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2018-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binding.StreamListenerAnnotationBeanPostProcessor; -import org.springframework.cloud.stream.binding.StreamListenerSetupMethodOrchestrator; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.cloud.stream.messaging.Source; -import org.springframework.context.annotation.Bean; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.util.ReflectionUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Soby Chacko - */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest -public class StreamListenerMethodSetupOrchestratorTests { - - @SpyBean - CustomOrchestrator customOrchestrator; - - @SpyBean - MultipleStreamListenerProcessor multipleStreamListenerProcessor; - - @SpyBean - StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor; - - @Test - @SuppressWarnings("unchecked") - public void testCustomStreamListenerOrchestratorAndDefaultTogetherInSameContext() - throws Exception { - - // Two StreamListener methods, so 2 invocations - verify(this.customOrchestrator, times(2)).supports(any()); - - Method method = this.multipleStreamListenerProcessor.getClass() - .getMethod("handleMessage"); - StreamListener streamListener = AnnotatedElementUtils.findMergedAnnotation(method, - StreamListener.class); - // verify that the invocation happened on the custom Orchestrator - verify(this.customOrchestrator).orchestrateStreamListenerSetupMethod( - streamListener, method, this.multipleStreamListenerProcessor); - - Method method1 = this.multipleStreamListenerProcessor.getClass() - .getMethod("produceString"); - StreamListener streamListener1 = AnnotatedElementUtils - .findMergedAnnotation(method, StreamListener.class); - - // Verify that the invocation did not happen on the custom orchestrator - verify(this.customOrchestrator, never()).orchestrateStreamListenerSetupMethod( - streamListener1, method1, this.multipleStreamListenerProcessor); - - Field field = ReflectionUtils.findField( - this.streamListenerAnnotationBeanPostProcessor.getClass(), - "streamListenerSetupMethodOrchestrators"); - ReflectionUtils.makeAccessible(field); - - Set field1; - field1 = (LinkedHashSet) ReflectionUtils - .getField(field, this.streamListenerAnnotationBeanPostProcessor); - List list = new ArrayList<>(field1); - - // Ensure that the custom orchestrator did not support this request - assertThat(list.get(0).supports(method1)).isEqualTo(false); - // Ensure that we are using the default Orchestrator in - // StreamListenerAnnoatationBeanPostProcessor - assertThat(list.get(1).supports(method1)).isEqualTo(true); - } - - public interface SomeProcessor { - - @Input(Sink.INPUT) - SubscribableChannel channel1(); - - @Input("foobar") - SubscribableChannel channel2(); - - @Output(Source.OUTPUT) - MessageChannel channel3(); - - } - - @EnableBinding(SomeProcessor.class) - @EnableAutoConfiguration - public static class MultipleStreamListenerProcessor { - - @StreamListener(Sink.INPUT) - public void handleMessage() { - } - - @StreamListener("foobar") - @SendTo("output") - public String produceString() { - return "foobar"; - } - - @Bean - public CustomOrchestrator myOrchestrator() { - return new CustomOrchestrator(); - } - - } - - static class CustomOrchestrator implements StreamListenerSetupMethodOrchestrator { - - @Override - public boolean supports(Method method) { - return method.getReturnType() != String.class; - } - - @Override - public void orchestrateStreamListenerSetupMethod(StreamListener streamListener, - Method method, Object bean) { - // stub method - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnMessageTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnMessageTests.java deleted file mode 100644 index 03fa383e9..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnMessageTests.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.SendTo; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -@RunWith(Parameterized.class) -public class StreamListenerMethodWithReturnMessageTests { - - private Class configClass; - - public StreamListenerMethodWithReturnMessageTests(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList(new Class[] { TestPojoWithMessageReturn1.class, - TestPojoWithMessageReturn2.class }); - } - - @Test - @SuppressWarnings("unchecked") - public void testReturnMessage() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run(this.configClass, - "--server.port=0", "--spring.jmx.enabled=false"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - TestPojoWithMessageReturn testPojoWithMessageReturn = context - .getBean(TestPojoWithMessageReturn.class); - Assertions.assertThat(testPojoWithMessageReturn.receivedPojos).hasSize(1); - Assertions.assertThat(testPojoWithMessageReturn.receivedPojos.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - assertThat(message).isNotNull(); - assertThat(message.getPayload()).contains("barbar" + id); - context.close(); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMessageReturn1 extends TestPojoWithMessageReturn { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Message receive(StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo(); - barPojo.setBar(fooPojo.getFoo()); - return MessageBuilder.withPayload(barPojo).setHeader("foo", "bar").build(); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestPojoWithMessageReturn2 extends TestPojoWithMessageReturn { - - @StreamListener(Processor.INPUT) - @Output(Processor.OUTPUT) - public Message receive(StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - StreamListenerTestUtils.BarPojo bazPojo = new StreamListenerTestUtils.BarPojo(); - bazPojo.setBar(fooPojo.getFoo()); - return MessageBuilder.withPayload(bazPojo).setHeader("foo", "bar").build(); - } - - } - - public static class TestPojoWithMessageReturn { - - List receivedPojos = new ArrayList<>(); - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnValueTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnValueTests.java deleted file mode 100644 index 8829ff44e..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerMethodWithReturnValueTests.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.SendTo; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Oleg Zhurakousky - */ -@RunWith(Parameterized.class) -public class StreamListenerMethodWithReturnValueTests { - - private Class configClass; - - public StreamListenerMethodWithReturnValueTests(Class configClass) { - this.configClass = configClass; - } - - @Parameterized.Parameters - public static Collection InputConfigs() { - return Arrays.asList( - new Class[] { TestStringProcessor1.class, TestStringProcessor2.class }); - } - - @Test - @SuppressWarnings("unchecked") - public void testReturn() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run(this.configClass, - "--server.port=0", "--spring.jmx.enabled=false"); - MessageCollector collector = context.getBean(MessageCollector.class); - Processor processor = context.getBean(Processor.class); - String id = UUID.randomUUID().toString(); - processor.input() - .send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json").build()); - Message message = (Message) collector - .forChannel(processor.output()).poll(1, TimeUnit.SECONDS); - TestStringProcessor testStringProcessor = context - .getBean(TestStringProcessor.class); - Assertions.assertThat(testStringProcessor.receivedPojos).hasSize(1); - Assertions.assertThat(testStringProcessor.receivedPojos.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - assertThat(message).isNotNull(); - assertThat(message.getPayload()).contains("barbar" + id); - context.close(); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestStringProcessor1 extends TestStringProcessor { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receive(StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - return fooPojo.getFoo(); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestStringProcessor2 extends TestStringProcessor { - - @StreamListener(Processor.INPUT) - @Output(Processor.OUTPUT) - public String receive(StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedPojos.add(fooPojo); - return fooPojo.getFoo(); - } - - } - - public static class TestStringProcessor { - - List receivedPojos = new ArrayList<>(); - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerTestUtils.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerTestUtils.java deleted file mode 100644 index 88dc892a6..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerTestUtils.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.SubscribableChannel; - -/** - * @author Ilayaperumal Gopinathan - */ -public class StreamListenerTestUtils { - - public interface FooInboundChannel1 { - - String INPUT = "foo1-input"; - - @Input(FooInboundChannel1.INPUT) - SubscribableChannel input(); - - } - - public interface FooOutboundChannel1 { - - String OUTPUT = "foo1-output"; - - @Output(FooOutboundChannel1.OUTPUT) - MessageChannel output(); - - } - - public static class FooPojo { - - private String foo; - - public String getFoo() { - return this.foo; - } - - public void setFoo(String foo) { - this.foo = foo; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("FooPojo{"); - sb.append("foo='").append(this.foo).append('\''); - sb.append('}'); - return sb.toString(); - } - - } - - public static class BarPojo { - - private String bar; - - public String getBar() { - return this.bar; - } - - public void setBar(String bar) { - this.bar = bar; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("BarPojo{"); - sb.append("bar='").append(this.bar).append('\''); - sb.append('}'); - return sb.toString(); - } - - } - - public static class PojoWithValidation { - - private String foo; - - public String getFoo() { - return this.foo; - } - - public void setFoo(String foo) { - this.foo = foo; - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithAnnotatedInputOutputArgsTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithAnnotatedInputOutputArgsTests.java deleted file mode 100644 index 2e2662dc9..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithAnnotatedInputOutputArgsTests.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binding.StreamListenerErrorMessages; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.support.MessageBuilder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.springframework.cloud.stream.binding.StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS; - -/** - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -public class StreamListenerWithAnnotatedInputOutputArgsTests { - - @Test - public void testInputOutputArgs() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestInputOutputArgs.class, "--server.port=0", - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - sendMessageAndValidate(context); - } - - @Test - public void testInputOutputArgsWithMoreParameters() { - try { - SpringApplication.run(TestInputOutputArgsWithMoreParameters.class, - "--server.port=0"); - fail("Expected exception: " + INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains(INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - @Test - public void testInputOutputArgsWithInvalidBindableTarget() { - try { - SpringApplication.run(TestInputOutputArgsWithInvalidBindableTarget.class, - "--server.port=0", "--spring.jmx.enabled=false"); - fail("Exception expected on using invalid bindable target as method parameter"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains( - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - @Test - public void testInputOutputArgsWithParameterOrderChanged() throws Exception { - ConfigurableApplicationContext context = SpringApplication.run( - TestInputOutputArgsWithParameterOrderChanged.class, "--server.port=0", - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - sendMessageAndValidate(context); - } - - @SuppressWarnings("unchecked") - private void sendMessageAndValidate(ConfigurableApplicationContext context) - throws InterruptedException { - Processor processor = context.getBean(Processor.class); - processor.input().send(MessageBuilder.withPayload("hello") - .setHeader("contentType", "text/plain").build()); - MessageCollector messageCollector = context.getBean(MessageCollector.class); - Message result = (Message) messageCollector - .forChannel(processor.output()).poll(1000, TimeUnit.MILLISECONDS); - assertThat(result).isNotNull(); - assertThat(result.getPayload()).isEqualTo("HELLO"); - context.close(); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestInputOutputArgs { - - @StreamListener - public void receive(@Input(Processor.INPUT) SubscribableChannel input, - @Output(Processor.OUTPUT) final MessageChannel output) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestInputOutputArgsWithMoreParameters { - - @StreamListener - public void receive(@Input(Processor.INPUT) SubscribableChannel input, - @Output(Processor.OUTPUT) final MessageChannel output, String someArg) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestInputOutputArgsWithInvalidBindableTarget { - - @StreamListener - public void receive(@Input("invalid") SubscribableChannel input, - @Output(Processor.OUTPUT) final MessageChannel output) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class TestInputOutputArgsWithParameterOrderChanged { - - @StreamListener - public void receive(@Output(Processor.OUTPUT) final MessageChannel output, - @Input("input") SubscribableChannel input) { - input.subscribe(new MessageHandler() { - @Override - public void handleMessage(Message message) throws MessagingException { - output.send(MessageBuilder - .withPayload(message.getPayload().toString().toUpperCase()) - .build()); - } - }); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithConditionsTest.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithConditionsTest.java deleted file mode 100644 index eb3cd7f75..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/StreamListenerWithConditionsTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.junit.Ignore; -import org.junit.Test; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binding.StreamListenerErrorMessages; -import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.handler.annotation.Payload; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -/** - * @author Marius Bogoevici - */ -public class StreamListenerWithConditionsTest { - - @Test - @Ignore - public void testAnnotatedArgumentsWithConditionalClass() throws Exception { - ConfigurableApplicationContext context = SpringApplication - .run(TestPojoWithAnnotatedArguments.class, "--server.port=0"); - - TestPojoWithAnnotatedArguments testPojoWithAnnotatedArguments = context - .getBean(TestPojoWithAnnotatedArguments.class); - Sink sink = context.getBean(Sink.class); - String id = UUID.randomUUID().toString(); - sink.input().send(MessageBuilder.withPayload("{\"foo\":\"barbar" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "foo").build()); - sink.input().send(MessageBuilder.withPayload("{\"bar\":\"foofoo" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "bar").build()); - sink.input().send(MessageBuilder.withPayload("{\"bar\":\"foofoo" + id + "\"}") - .setHeader("contentType", "application/json") - .setHeader("testHeader", "testValue").setHeader("type", "qux").build()); - assertThat(testPojoWithAnnotatedArguments.receivedFoo).hasSize(1); - assertThat(testPojoWithAnnotatedArguments.receivedFoo.get(0)) - .hasFieldOrPropertyWithValue("foo", "barbar" + id); - assertThat(testPojoWithAnnotatedArguments.receivedBar).hasSize(1); - assertThat(testPojoWithAnnotatedArguments.receivedBar.get(0)) - .hasFieldOrPropertyWithValue("bar", "foofoo" + id); - context.close(); - } - - @Test - public void testConditionalFailsWithReturnValue() throws Exception { - try { - ConfigurableApplicationContext context = SpringApplication.run( - TestConditionalOnMethodWithReturnValueFails.class, "--server.port=0"); - context.close(); - fail("Context creation failure expected"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains( - StreamListenerErrorMessages.CONDITION_ON_METHOD_RETURNING_VALUE); - } - } - - @Test - public void testConditionalFailsWithDeclarativeMethod() throws Exception { - try { - ConfigurableApplicationContext context = SpringApplication.run( - TestConditionalOnDeclarativeMethodFails.class, "--server.port=0"); - context.close(); - fail("Context creation failure expected"); - } - catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains( - StreamListenerErrorMessages.CONDITION_ON_DECLARATIVE_METHOD); - } - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestPojoWithAnnotatedArguments { - - List receivedFoo = new ArrayList<>(); - - List receivedBar = new ArrayList<>(); - - @StreamListener(value = Sink.INPUT, condition = "headers['type']=='foo'") - public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo) { - this.receivedFoo.add(fooPojo); - } - - @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bar'") - public void receive(@Payload StreamListenerTestUtils.BarPojo barPojo) { - this.receivedBar.add(barPojo); - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestConditionalOnDeclarativeMethodFails { - - @StreamListener(condition = "headers['type']=='foo'") - public void receive(@Input("input") MessageChannel input) { - // do nothing - } - - } - - @EnableBinding(Sink.class) - @EnableAutoConfiguration - public static class TestConditionalOnMethodWithReturnValueFails { - - @StreamListener(value = Sink.INPUT, condition = "headers['type']=='foo'") - public String receive(String value) { - return null; - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java deleted file mode 100644 index 33c9094d8..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2017-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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config; - -import java.util.concurrent.TimeUnit; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binder.BinderFactory; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.test.binder.TestSupportBinder; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Marius Bogoevici - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - * @since 1.2 - */ -@RunWith(SpringJUnit4ClassRunner.class) -// @checkstyle:off -@SpringBootTest(classes = TextPlainToJsonConversionTest.FooProcessor.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) -// @checkstyle:on -public class TextPlainToJsonConversionTest { - - @Autowired - private Processor testProcessor; - - @Autowired - private BinderFactory binderFactory; - - private ObjectMapper mapper = new ObjectMapper(); - - @SuppressWarnings("unchecked") - @Test - public void testNoContentTypeToJsonConversionOnInput() throws Exception { - this.testProcessor.input() - .send(MessageBuilder.withPayload("{\"name\":\"Bar\"}").build()); - Message received = (Message) ((TestSupportBinder) this.binderFactory - .getBinder(null, MessageChannel.class)).messageCollector() - .forChannel(this.testProcessor.output()) - .poll(1, TimeUnit.SECONDS); - assertThat(received).isNotNull(); - Foo foo = this.mapper.readValue(received.getPayload(), Foo.class); - assertThat(foo.getName()).isEqualTo("transformed-Bar"); - } - - /** - * @since 2.0: Conversion from text/plain -> json is no longer supported. Strict - * contentType only. - */ - @Test(expected = MessagingException.class) - public void testTextPlainToJsonConversionOnInput() { - this.testProcessor.input().send(MessageBuilder.withPayload("{\"name\":\"Bar\"}") - .setHeader(MessageHeaders.CONTENT_TYPE, "text/plain").build()); - } - - @EnableBinding(Processor.class) - @EnableAutoConfiguration - public static class FooProcessor { - - @StreamListener("input") - @SendTo("output") - public Foo consume(Foo foo) { - Foo returnFoo = new Foo(); - returnFoo.setName("transformed-" + foo.getName()); - return returnFoo; - } - - } - - public static class Foo { - - private String name; - - public Foo() { - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "Foo{name='" + this.name + "'}"; - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java.todo b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java.todo new file mode 100644 index 000000000..cf877e9ee --- /dev/null +++ b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/TextPlainToJsonConversionTest.java.todo @@ -0,0 +1,123 @@ +///* +// * Copyright 2017-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. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.springframework.cloud.stream.config; +// +//import java.util.concurrent.TimeUnit; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import org.junit.Test; +//import org.junit.runner.RunWith; +// +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +//import org.springframework.boot.test.context.SpringBootTest; +//import org.springframework.cloud.stream.annotation.EnableBinding; +//import org.springframework.cloud.stream.annotation.StreamListener; +//import org.springframework.cloud.stream.binder.BinderFactory; +//import org.springframework.cloud.stream.messaging.Processor; +//import org.springframework.cloud.stream.test.binder.TestSupportBinder; +//import org.springframework.integration.support.MessageBuilder; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.MessageChannel; +//import org.springframework.messaging.MessageHeaders; +//import org.springframework.messaging.MessagingException; +//import org.springframework.messaging.handler.annotation.SendTo; +//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +///** +// * @author Marius Bogoevici +// * @author Vinicius Carvalho +// * @author Oleg Zhurakousky +// * @since 1.2 +// */ +//@RunWith(SpringJUnit4ClassRunner.class) +//// @checkstyle:off +//@SpringBootTest(classes = TextPlainToJsonConversionTest.FooProcessor.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) +//// @checkstyle:on +//public class TextPlainToJsonConversionTest { +// +// @Autowired +// private Processor testProcessor; +// +// @Autowired +// private BinderFactory binderFactory; +// +// private ObjectMapper mapper = new ObjectMapper(); +// +// @SuppressWarnings("unchecked") +// @Test +// public void testNoContentTypeToJsonConversionOnInput() throws Exception { +// this.testProcessor.input() +// .send(MessageBuilder.withPayload("{\"name\":\"Bar\"}").build()); +// Message received = (Message) ((TestSupportBinder) this.binderFactory +// .getBinder(null, MessageChannel.class)).messageCollector() +// .forChannel(this.testProcessor.output()) +// .poll(1, TimeUnit.SECONDS); +// assertThat(received).isNotNull(); +// Foo foo = this.mapper.readValue(received.getPayload(), Foo.class); +// assertThat(foo.getName()).isEqualTo("transformed-Bar"); +// } +// +// /** +// * @since 2.0: Conversion from text/plain -> json is no longer supported. Strict +// * contentType only. +// */ +// @Test(expected = MessagingException.class) +// public void testTextPlainToJsonConversionOnInput() { +// this.testProcessor.input().send(MessageBuilder.withPayload("{\"name\":\"Bar\"}") +// .setHeader(MessageHeaders.CONTENT_TYPE, "text/plain").build()); +// } +// +// @EnableBinding(Processor.class) +// @EnableAutoConfiguration +// public static class FooProcessor { +// +// @StreamListener("input") +// @SendTo("output") +// public Foo consume(Foo foo) { +// Foo returnFoo = new Foo(); +// returnFoo.setName("transformed-" + foo.getName()); +// return returnFoo; +// } +// +// } +// +// public static class Foo { +// +// private String name; +// +// public Foo() { +// } +// +// public String getName() { +// return this.name; +// } +// +// public void setName(String name) { +// this.name = name; +// } +// +// @Override +// public String toString() { +// return "Foo{name='" + this.name + "'}"; +// } +// +// } +// +//} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java deleted file mode 100644 index 3c341fd0e..000000000 --- a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2017-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.config.contentType; - -import java.util.LinkedList; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.messaging.Source; -import org.springframework.cloud.stream.test.binder.MessageCollector; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.support.MessageBuilder; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.handler.annotation.Headers; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Vinicius Carvalho - * @author Oleg Zhurakousky - */ -@SuppressWarnings("unchecked") -public class ContentTypeTests { - - private ObjectMapper mapper = new ObjectMapper(); - - @Test - public void testSendWithDefaultContentType() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", - "--spring.jmx.enabled=false")) { - - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - User user = new User("Alice"); - source.output().send(MessageBuilder.withPayload(user).build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - User received = this.mapper.readValue(message.getPayload(), User.class); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_JSON)); - assertThat(user.getName()).isEqualTo(received.getName()); - } - } - - @Test - public void testSendJsonAsString() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", - "--spring.jmx.enabled=false")) { - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - User user = new User("Alice"); - String json = this.mapper.writeValueAsString(user); - source.output().send(MessageBuilder.withPayload(user).build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_JSON)); - assertThat(json).isEqualTo(message.getPayload()); - } - } - - @Test - public void testSendJsonString() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", - "--spring.jmx.enabled=false")) { - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - source.output().send(MessageBuilder.withPayload("foo").build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_JSON)); - assertThat("foo").isEqualTo(message.getPayload()); - } - } - - @Test - public void testSendBynaryData() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", - "--spring.jmx.enabled=false")) { - - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - byte[] data = new byte[] { 0, 1, 2, 3 }; - source.output() - .send(MessageBuilder.withPayload(data) - .setHeader(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.APPLICATION_OCTET_STREAM) - .build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.APPLICATION_OCTET_STREAM)); - assertThat(message.getPayload()).isEqualTo(data); - } - } - - @Test - public void testSendBinaryDataWithContentType() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.output.contentType=image/jpeg")) { - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - byte[] data = new byte[] { 0, 1, 2, 3 }; - source.output().send(MessageBuilder.withPayload(data).build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat(message.getPayload()).isEqualTo(data); - } - } - - @Test - public void testSendBinaryDataWithContentTypeUsingHeaders() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", - "--spring.jmx.enabled=false")) { - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - byte[] data = new byte[] { 0, 1, 2, 3 }; - source.output().send(MessageBuilder.withPayload(data) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_JPEG) - .build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.IMAGE_JPEG)); - assertThat(message.getPayload()).isEqualTo(data); - } - } - - @Test - public void testSendStringType() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SourceApplication.class, "--server.port=0", "--spring.jmx.enabled=false", - "--spring.cloud.stream.bindings.output.contentType=text/plain")) { - MessageCollector collector = context.getBean(MessageCollector.class); - Source source = context.getBean(Source.class); - User user = new User("Alice"); - source.output().send(MessageBuilder.withPayload(user).build()); - Message message = (Message) collector - .forChannel(source.output()).poll(1, TimeUnit.SECONDS); - assertThat( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) - .includes(MimeTypeUtils.TEXT_PLAIN)); - assertThat(message.getPayload()).isEqualTo(user.toString()); - } - } - - @Test - public void testReceiveWithDefaults() throws Exception { - try (ConfigurableApplicationContext context = SpringApplication.run( - SinkApplication.class, "--server.port=0", "--spring.jmx.enabled=false")) { - TestSink testSink = context.getBean(TestSink.class); - SinkApplication sourceApp = context.getBean(SinkApplication.class); - User user = new User("Alice"); - testSink.pojo().send(MessageBuilder - .withPayload(this.mapper.writeValueAsBytes(user)).build()); - Map headers = (Map) sourceApp.arguments.pop(); - User received = (User) sourceApp.arguments.pop(); - assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) - .includes(MimeTypeUtils.APPLICATION_JSON)); - assertThat(user.getName()).isEqualTo(received.getName()); - } - } - - @Test - public void testReceiveRawWithDifferentContentTypes() { - try (ConfigurableApplicationContext context = SpringApplication.run( - SinkApplication.class, "--server.port=0", "--spring.jmx.enabled=false")) { - TestSink testSink = context.getBean(TestSink.class); - SinkApplication sourceApp = context.getBean(SinkApplication.class); - testSink.raw().send(MessageBuilder.withPayload(new byte[4]) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_JPEG) - .build()); - testSink.raw().send(MessageBuilder.withPayload(new byte[4]) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_GIF) - .build()); - Map headers = (Map) sourceApp.arguments.pop(); - sourceApp.arguments.pop(); - assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) - .includes(MimeTypeUtils.IMAGE_GIF)); - headers = (Map) sourceApp.arguments.pop(); - sourceApp.arguments.pop(); - assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) - .includes(MimeTypeUtils.IMAGE_JPEG)); - } - } - - - public interface TestSink { - - @Input("POJO_INPUT") - SubscribableChannel pojo(); - - @Input("STRING_INPUT") - SubscribableChannel string(); - - @Input("TUPLE_INPUT") - SubscribableChannel tuple(); - - @Input("RAW_INPUT") - SubscribableChannel raw(); - - } - - @EnableBinding(Source.class) - @SpringBootApplication - public static class SourceApplication { - - } - - @EnableBinding(TestSink.class) - @SpringBootApplication - public static class SinkApplication { - - public LinkedList arguments = new LinkedList<>(); - - @StreamListener("POJO_INPUT") - public void receive(User user, @Headers Map headers) { - this.arguments.push(user); - this.arguments.push(headers); - } - - @StreamListener("STRING_INPUT") - public void receive(String string) { - } - - @StreamListener("RAW_INPUT") - public void receive(byte[] data, @Headers Map headers) { - this.arguments.push(data); - this.arguments.push(headers); - } - - } - -} diff --git a/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java.todo b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java.todo new file mode 100644 index 000000000..06ed93ff8 --- /dev/null +++ b/spring-cloud-stream-integration-tests/src/test/java/org/springframework/cloud/stream/config/contentType/ContentTypeTests.java.todo @@ -0,0 +1,272 @@ +///* +// * Copyright 2017-2019 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. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.springframework.cloud.stream.config.contentType; +// +//import java.util.LinkedList; +//import java.util.Map; +//import java.util.concurrent.TimeUnit; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import org.junit.Test; +// +//import org.springframework.boot.SpringApplication; +//import org.springframework.boot.autoconfigure.SpringBootApplication; +//import org.springframework.cloud.stream.annotation.EnableBinding; +//import org.springframework.cloud.stream.annotation.Input; +//import org.springframework.cloud.stream.annotation.StreamListener; +//import org.springframework.cloud.stream.messaging.Source; +//import org.springframework.cloud.stream.test.binder.MessageCollector; +//import org.springframework.context.ConfigurableApplicationContext; +//import org.springframework.integration.support.MessageBuilder; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.MessageHeaders; +//import org.springframework.messaging.SubscribableChannel; +//import org.springframework.messaging.handler.annotation.Headers; +//import org.springframework.util.MimeType; +//import org.springframework.util.MimeTypeUtils; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +///** +// * @author Vinicius Carvalho +// * @author Oleg Zhurakousky +// */ +//@SuppressWarnings("unchecked") +//public class ContentTypeTests { +// +// private ObjectMapper mapper = new ObjectMapper(); +// +// @Test +// public void testSendWithDefaultContentType() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", +// "--spring.jmx.enabled=false")) { +// +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// User user = new User("Alice"); +// source.output().send(MessageBuilder.withPayload(user).build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// User received = this.mapper.readValue(message.getPayload(), User.class); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.APPLICATION_JSON)); +// assertThat(user.getName()).isEqualTo(received.getName()); +// } +// } +// +// @Test +// public void testSendJsonAsString() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", +// "--spring.jmx.enabled=false")) { +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// User user = new User("Alice"); +// String json = this.mapper.writeValueAsString(user); +// source.output().send(MessageBuilder.withPayload(user).build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.APPLICATION_JSON)); +// assertThat(json).isEqualTo(message.getPayload()); +// } +// } +// +// @Test +// public void testSendJsonString() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", +// "--spring.jmx.enabled=false")) { +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// source.output().send(MessageBuilder.withPayload("foo").build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.APPLICATION_JSON)); +// assertThat("foo").isEqualTo(message.getPayload()); +// } +// } +// +// @Test +// public void testSendBynaryData() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", +// "--spring.jmx.enabled=false")) { +// +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// byte[] data = new byte[] { 0, 1, 2, 3 }; +// source.output() +// .send(MessageBuilder.withPayload(data) +// .setHeader(MessageHeaders.CONTENT_TYPE, +// MimeTypeUtils.APPLICATION_OCTET_STREAM) +// .build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.APPLICATION_OCTET_STREAM)); +// assertThat(message.getPayload()).isEqualTo(data); +// } +// } +// +// @Test +// public void testSendBinaryDataWithContentType() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", "--spring.jmx.enabled=false", +// "--spring.cloud.stream.bindings.output.contentType=image/jpeg")) { +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// byte[] data = new byte[] { 0, 1, 2, 3 }; +// source.output().send(MessageBuilder.withPayload(data).build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat(message.getPayload()).isEqualTo(data); +// } +// } +// +// @Test +// public void testSendBinaryDataWithContentTypeUsingHeaders() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", +// "--spring.jmx.enabled=false")) { +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// byte[] data = new byte[] { 0, 1, 2, 3 }; +// source.output().send(MessageBuilder.withPayload(data) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_JPEG) +// .build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.IMAGE_JPEG)); +// assertThat(message.getPayload()).isEqualTo(data); +// } +// } +// +// @Test +// public void testSendStringType() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SourceApplication.class, "--server.port=0", "--spring.jmx.enabled=false", +// "--spring.cloud.stream.bindings.output.contentType=text/plain")) { +// MessageCollector collector = context.getBean(MessageCollector.class); +// Source source = context.getBean(Source.class); +// User user = new User("Alice"); +// source.output().send(MessageBuilder.withPayload(user).build()); +// Message message = (Message) collector +// .forChannel(source.output()).poll(1, TimeUnit.SECONDS); +// assertThat( +// message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class) +// .includes(MimeTypeUtils.TEXT_PLAIN)); +// assertThat(message.getPayload()).isEqualTo(user.toString()); +// } +// } +// +// @Test +// public void testReceiveWithDefaults() throws Exception { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SinkApplication.class, "--server.port=0", "--spring.jmx.enabled=false")) { +// TestSink testSink = context.getBean(TestSink.class); +// SinkApplication sourceApp = context.getBean(SinkApplication.class); +// User user = new User("Alice"); +// testSink.pojo().send(MessageBuilder +// .withPayload(this.mapper.writeValueAsBytes(user)).build()); +// Map headers = (Map) sourceApp.arguments.pop(); +// User received = (User) sourceApp.arguments.pop(); +// assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) +// .includes(MimeTypeUtils.APPLICATION_JSON)); +// assertThat(user.getName()).isEqualTo(received.getName()); +// } +// } +// +// @Test +// public void testReceiveRawWithDifferentContentTypes() { +// try (ConfigurableApplicationContext context = SpringApplication.run( +// SinkApplication.class, "--server.port=0", "--spring.jmx.enabled=false")) { +// TestSink testSink = context.getBean(TestSink.class); +// SinkApplication sourceApp = context.getBean(SinkApplication.class); +// testSink.raw().send(MessageBuilder.withPayload(new byte[4]) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_JPEG) +// .build()); +// testSink.raw().send(MessageBuilder.withPayload(new byte[4]) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.IMAGE_GIF) +// .build()); +// Map headers = (Map) sourceApp.arguments.pop(); +// sourceApp.arguments.pop(); +// assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) +// .includes(MimeTypeUtils.IMAGE_GIF)); +// headers = (Map) sourceApp.arguments.pop(); +// sourceApp.arguments.pop(); +// assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE)) +// .includes(MimeTypeUtils.IMAGE_JPEG)); +// } +// } +// +// +// public interface TestSink { +// +// @Input("POJO_INPUT") +// SubscribableChannel pojo(); +// +// @Input("STRING_INPUT") +// SubscribableChannel string(); +// +// @Input("TUPLE_INPUT") +// SubscribableChannel tuple(); +// +// @Input("RAW_INPUT") +// SubscribableChannel raw(); +// +// } +// +// @EnableBinding(Source.class) +// @SpringBootApplication +// public static class SourceApplication { +// +// } +// +// @EnableBinding(TestSink.class) +// @SpringBootApplication +// public static class SinkApplication { +// +// public LinkedList arguments = new LinkedList<>(); +// +// @StreamListener("POJO_INPUT") +// public void receive(User user, @Headers Map headers) { +// this.arguments.push(user); +// this.arguments.push(headers); +// } +// +// @StreamListener("STRING_INPUT") +// public void receive(String string) { +// } +// +// @StreamListener("RAW_INPUT") +// public void receive(byte[] data, @Headers Map headers) { +// this.arguments.push(data); +// this.arguments.push(headers); +// } +// +// } +// +//} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/StreamListener.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/StreamListener.java deleted file mode 100644 index bad7b106a..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/annotation/StreamListener.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.cloud.stream.binding.StreamListenerParameterAdapter; -import org.springframework.core.annotation.AliasFor; -import org.springframework.messaging.handler.annotation.MessageMapping; - -/** - * NOTE: It is no longer recommended to use StreamListener in favor of functional programming model. - * It will be deprecated and subsequently removed in the future - *
- *
- * Annotation that marks a method to be a listener to inputs declared via - * {@link EnableBinding} (e.g. channels). - * - * Annotated methods are allowed to have flexible signatures, which determine how the - * method is invoked and how their return results are processed. This annotation can be - * applied for two separate classes of methods. - * - *

Declarative mode

- * - * A method is considered declarative if all its method parameter types and return type - * (if not void) are binding targets or conversion targets from binding targets via a - * registered {@link StreamListenerParameterAdapter}. - * - * Only declarative methods can have binding targets or conversion targets as arguments - * and return type. - * - * Declarative methods must specify what inputs and outputs correspond to their arguments - * and return type, and can do this in one of the following ways. - * - *
    - *
  • By using either the {@link Input} or {@link Output} annotation for each of the - * parameters and the {@link Output} annotation on the method for the return type (if - * applicable). The use of annotations in this case is mandatory. In this case the - * {@link StreamListener} annotation must not specify a value.
  • - *
  • By setting an {@link Input} bound target as the annotation value of - * {@link StreamListener} and using - * {@link org.springframework.messaging.handler.annotation.SendTo} on the method for - * the return type (if applicable). In this case the method must have exactly one - * parameter, corresponding to an input. - *
  • - *
- * - * An example of declarative method signature using the former idiom is as follows: - * - *
- * @StreamListener
- * public @Output("joined") Flux<String> join(
- *       @Input("input1") Flux<String> input1,
- *       @Input("input2") Flux<String> input2) {
- *   // ... join the two input streams via functional operators
- * }
- * 
- * - * An example of declarative method signature using the latter idiom is as follows: - * - *
- * @StreamListener(Processor.INPUT)
- * @SendTo(Processor.OUTPUT)
- * public Flux<String> convert(Flux<String> input) {
- *     return input.map(String::toUppercase);
- * }
- * 
- * - * Declarative methods are invoked only once, when the context is refreshed. - * - *

Individual message handler mode

- * - * Non declarative methods are treated as message handler based, and are invoked for each - * incoming message received from that target. In this case, the method can have a - * flexible signature, as described by {@link MessageMapping}. - * - * If the method returns a {@link org.springframework.messaging.Message}, the result will - * be automatically sent to a binding target, as follows: - *
    - *
  • A result of the type {@link org.springframework.messaging.Message} will be sent - * as-is
  • - *
  • All other results will become the payload of a - * {@link org.springframework.messaging.Message}
  • - *
- * - * The output binding target where the return message is sent is determined by consulting - * in the following order: - *
    - *
  • The {@link org.springframework.messaging.MessageHeaders} of the resulting - * message.
  • - *
  • The value set on the - * {@link org.springframework.messaging.handler.annotation.SendTo} annotation, if - * present
  • - *
- * - * An example of individual message handler signature is as follows: - * - *
- * @StreamListener(Processor.INPUT)
- * @SendTo(Processor.OUTPUT)
- * public String convert(String input) {
- * 		return input.toUppercase();
- * }
- * 
- * - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Gary Russell - * @see MessageMapping - * @see EnableBinding - * @see org.springframework.messaging.handler.annotation.SendTo - * - * @deprecated as of 3.1 in favor of functional programming model - */ -@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@MessageMapping -@Documented -@Deprecated -public @interface StreamListener { - - /** - * The name of the binding target (e.g. channel) that the method subscribes to. - * @return the name of the binding target. - */ - @AliasFor("target") - String value() default ""; - - /** - * The name of the binding target (e.g. channel) that the method subscribes to. - * @return the name of the binding target. - */ - @AliasFor("value") - String target() default ""; - - /** - * A condition that must be met by all items that are dispatched to this method. - * @return a SpEL expression that must evaluate to a {@code boolean} value. - */ - String condition() default ""; - - /** - * When "true" (default), and a {@code @SendTo} annotation is present, copy the - * inbound headers to the outbound message (if the header is absent on the outbound - * message). Can be an expression ({@code #{...}}) or property placeholder. Must - * resolve to a boolean or a string that is parsed by {@code Boolean.parseBoolean()}. - * An expression that resolves to {@code null} is interpreted to mean {@code false}. - * - * The expression is evaluated during application initialization, and not for each - * individual message. - * - * Prior to version 1.3.0, the default value used to be "false" and headers were not - * propagated by default. - * - * Starting with version 1.3.0, the default value is "true". - * - * @since 1.2.3 - * @return {@link Boolean} in a String format - */ - String copyHeaders() default "true"; - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/DispatchingStreamListenerMessageHandler.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/DispatchingStreamListenerMessageHandler.java deleted file mode 100644 index 9efd38543..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/DispatchingStreamListenerMessageHandler.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2017-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.Expression; -import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; - -/** - * An {@link AbstractReplyProducingMessageHandler} that delegates to a collection of - * internal {@link ConditionalStreamListenerMessageHandlerWrapper} instances, executing - * the ones that match the given expression. - * - * @author Marius Bogoevici - * @since 1.2 - */ -final class DispatchingStreamListenerMessageHandler - extends AbstractReplyProducingMessageHandler { - - private final List handlerMethods; - - private final boolean evaluateExpressions; - - private final EvaluationContext evaluationContext; - - DispatchingStreamListenerMessageHandler( - Collection handlerMethods, - EvaluationContext evaluationContext) { - Assert.notEmpty(handlerMethods, "'handlerMethods' cannot be empty"); - this.handlerMethods = Collections - .unmodifiableList(new ArrayList<>(handlerMethods)); - boolean evaluateExpressions = false; - for (ConditionalStreamListenerMessageHandlerWrapper handlerMethod : handlerMethods) { - if (handlerMethod.getCondition() != null) { - evaluateExpressions = true; - break; - } - } - this.evaluateExpressions = evaluateExpressions; - if (evaluateExpressions) { - Assert.notNull(evaluationContext, - "'evaluationContext' cannot be null if conditions are used"); - } - this.evaluationContext = evaluationContext; - } - - @Override - protected boolean shouldCopyRequestHeaders() { - return false; - } - - @Override - protected Object handleRequestMessage(Message requestMessage) { - List matchingHandlers = this.evaluateExpressions - ? findMatchingHandlers(requestMessage) : this.handlerMethods; - if (matchingHandlers.size() == 0) { - if (this.logger.isWarnEnabled()) { - this.logger.warn( - "Cannot find a @StreamListener matching for message with id: " - + requestMessage.getHeaders().getId()); - } - return null; - } - else if (matchingHandlers.size() > 1) { - for (ConditionalStreamListenerMessageHandlerWrapper matchingMethod : matchingHandlers) { - matchingMethod.getStreamListenerMessageHandler() - .handleMessage(requestMessage); - } - return null; - } - else { - final ConditionalStreamListenerMessageHandlerWrapper singleMatchingHandler = matchingHandlers - .get(0); - singleMatchingHandler.getStreamListenerMessageHandler() - .handleMessage(requestMessage); - return null; - } - } - - private List findMatchingHandlers( - Message message) { - ArrayList matchingMethods = new ArrayList<>(); - for (ConditionalStreamListenerMessageHandlerWrapper wrapper : this.handlerMethods) { - if (wrapper.getCondition() == null) { - matchingMethods.add(wrapper); - } - else { - boolean conditionMetOnMessage = wrapper.getCondition() - .getValue(this.evaluationContext, message, Boolean.class); - if (conditionMetOnMessage) { - matchingMethods.add(wrapper); - } - } - } - return matchingMethods; - } - - static class ConditionalStreamListenerMessageHandlerWrapper { - - private final Expression condition; - - private final StreamListenerMessageHandler streamListenerMessageHandler; - - ConditionalStreamListenerMessageHandlerWrapper(Expression condition, - StreamListenerMessageHandler streamListenerMessageHandler) { - Assert.notNull(streamListenerMessageHandler, - "the message handler cannot be null"); - Assert.isTrue(condition == null || streamListenerMessageHandler.isVoid(), - "cannot specify a condition and a return value at the same time"); - this.condition = condition; - this.streamListenerMessageHandler = streamListenerMessageHandler; - } - - public Expression getCondition() { - return this.condition; - } - - public boolean isVoid() { - return this.streamListenerMessageHandler.isVoid(); - } - - public StreamListenerMessageHandler getStreamListenerMessageHandler() { - return this.streamListenerMessageHandler; - } - - } - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/MessageChannelStreamListenerResultAdapter.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/MessageChannelStreamListenerResultAdapter.java deleted file mode 100644 index 16ce41dff..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/MessageChannelStreamListenerResultAdapter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.io.Closeable; -import java.io.IOException; - -import org.springframework.integration.handler.BridgeHandler; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.SubscribableChannel; - -/** - * A {@link StreamListenerResultAdapter} used for bridging an - * {@link org.springframework.cloud.stream.annotation.Output} {@link MessageChannel} to a - * bound {@link MessageChannel}. - * - * @author Marius Bogoevici - * @author Soby Chacko - */ -public class MessageChannelStreamListenerResultAdapter - implements StreamListenerResultAdapter { - - @Override - public boolean supports(Class resultType, Class bindingTarget) { - return MessageChannel.class.isAssignableFrom(resultType) - && MessageChannel.class.isAssignableFrom(bindingTarget); - } - - @Override - public Closeable adapt(MessageChannel streamListenerResult, - MessageChannel bindingTarget) { - BridgeHandler handler = new BridgeHandler(); - handler.setOutputChannel(bindingTarget); - handler.afterPropertiesSet(); - ((SubscribableChannel) streamListenerResult).subscribe(handler); - - return new NoOpCloseeable(); - } - - private static final class NoOpCloseeable implements Closeable { - - @Override - public void close() throws IOException { - - } - - } - -} 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 deleted file mode 100644 index b4d9b3e40..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerAnnotationBeanPostProcessor.java +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright 2016-2020 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import org.springframework.aop.framework.Advised; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanInitializationException; -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.beans.factory.config.BeanExpressionResolver; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.config.SpringIntegrationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.integration.context.IntegrationContextUtils; -import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.SubscribableChannel; -import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory; -import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; -import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -/** - * {@link BeanPostProcessor} that handles {@link StreamListener} annotations found on bean - * methods. - * - * @author Marius Bogoevici - * @author Ilayaperumal Gopinathan - * @author Soby Chacko - * @author Oleg Zhurakousky - */ -public class StreamListenerAnnotationBeanPostProcessor implements BeanPostProcessor, - ApplicationContextAware, SmartInitializingSingleton { - - private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser(); - - // @checkstyle:off - private final MultiValueMap mappedListenerMethods = new LinkedMultiValueMap<>(); - - // @checkstyle:on - - private final Set streamListenerCallbacks = new HashSet<>(); - - // == dependencies that are injected in 'afterSingletonsInstantiated' to avoid early - // initialization - //private DestinationResolver binderAwareChannelResolver; - - private MessageHandlerMethodFactory messageHandlerMethodFactory; - - // == end dependencies - private SpringIntegrationProperties springIntegrationProperties; - - private ConfigurableApplicationContext applicationContext; - - private BeanExpressionResolver resolver; - - private BeanExpressionContext expressionContext; - - private Set streamListenerSetupMethodOrchestrators = new LinkedHashSet<>(); - - private boolean streamListenerPresent; - - @Override - public final void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = (ConfigurableApplicationContext) applicationContext; - this.resolver = this.applicationContext.getBeanFactory() - .getBeanExpressionResolver(); - this.expressionContext = new BeanExpressionContext( - this.applicationContext.getBeanFactory(), null); - } - - @Override - public final void afterSingletonsInstantiated() { - if (!this.streamListenerPresent) { - return; - } - this.injectAndPostProcessDependencies(); - EvaluationContext evaluationContext = IntegrationContextUtils - .getEvaluationContext(this.applicationContext.getBeanFactory()); - for (Map.Entry> mappedBindingEntry : this.mappedListenerMethods - .entrySet()) { - ArrayList handlers; - handlers = new ArrayList<>(); - for (StreamListenerHandlerMethodMapping mapping : mappedBindingEntry - .getValue()) { - final InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory - .createInvocableHandlerMethod(mapping.getTargetBean(), - checkProxy(mapping.getMethod(), mapping.getTargetBean())); - StreamListenerMessageHandler streamListenerMessageHandler = new StreamListenerMessageHandler( - invocableHandlerMethod, - resolveExpressionAsBoolean(mapping.getCopyHeaders(), - "copyHeaders"), - this.springIntegrationProperties - .getMessageHandlerNotPropagatedHeaders()); - streamListenerMessageHandler - .setApplicationContext(this.applicationContext); - streamListenerMessageHandler - .setBeanFactory(this.applicationContext.getBeanFactory()); - if (StringUtils.hasText(mapping.getDefaultOutputChannel())) { - streamListenerMessageHandler - .setOutputChannelName(mapping.getDefaultOutputChannel()); - } - streamListenerMessageHandler.afterPropertiesSet(); - if (StringUtils.hasText(mapping.getCondition())) { - String conditionAsString = resolveExpressionAsString( - mapping.getCondition(), "condition"); - Expression condition = SPEL_EXPRESSION_PARSER - .parseExpression(conditionAsString); - handlers.add( - new DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper( - condition, streamListenerMessageHandler)); - } - else { - handlers.add( - new DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper( - null, streamListenerMessageHandler)); - } - } - if (handlers.size() > 1) { - for (DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper handler : handlers) { - Assert.isTrue(handler.isVoid(), - StreamListenerErrorMessages.MULTIPLE_VALUE_RETURNING_METHODS); - } - } - AbstractReplyProducingMessageHandler handler; - - if (handlers.size() > 1 || handlers.get(0).getCondition() != null) { - handler = new DispatchingStreamListenerMessageHandler(handlers, - evaluationContext); - } - else { - handler = handlers.get(0).getStreamListenerMessageHandler(); - } - handler.setApplicationContext(this.applicationContext); - //handler.setChannelResolver(this.binderAwareChannelResolver); - handler.afterPropertiesSet(); - this.applicationContext.getBeanFactory().registerSingleton( - handler.getClass().getSimpleName() + handler.hashCode(), handler); - this.applicationContext - .getBean(mappedBindingEntry.getKey(), SubscribableChannel.class) - .subscribe(handler); - } - this.mappedListenerMethods.clear(); - } - - @Override - public final Object postProcessAfterInitialization(Object bean, final String beanName) - throws BeansException { - Class targetClass = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) - : bean.getClass(); - Method[] uniqueDeclaredMethods = ReflectionUtils - .getUniqueDeclaredMethods(targetClass, ReflectionUtils.USER_DECLARED_METHODS); - for (Method method : uniqueDeclaredMethods) { - StreamListener streamListener = AnnotatedElementUtils - .findMergedAnnotation(method, StreamListener.class); - if (streamListener != null) { - this.streamListenerPresent = true; - this.streamListenerCallbacks.add(() -> { - Assert.isTrue(method.getAnnotation(Input.class) == null, - StreamListenerErrorMessages.INPUT_AT_STREAM_LISTENER); - this.doPostProcess(streamListener, method, bean); - }); - } - } - return bean; - } - - /** - * Extension point, allowing subclasses to customize the {@link StreamListener} - * annotation detected by the postprocessor. - * @param originalAnnotation the original annotation - * @param annotatedMethod the method on which the annotation has been found - * @return the postprocessed {@link StreamListener} annotation - */ - protected StreamListener postProcessAnnotation(StreamListener originalAnnotation, - Method annotatedMethod) { - return originalAnnotation; - } - - private void doPostProcess(StreamListener streamListener, Method method, - Object bean) { - streamListener = postProcessAnnotation(streamListener, method); - Optional orchestratorOptional; - orchestratorOptional = this.streamListenerSetupMethodOrchestrators.stream() - .filter(t -> t.supports(method)).findFirst(); - Assert.isTrue(orchestratorOptional.isPresent(), - "A matching StreamListenerSetupMethodOrchestrator must be present"); - StreamListenerSetupMethodOrchestrator streamListenerSetupMethodOrchestrator = orchestratorOptional - .get(); - streamListenerSetupMethodOrchestrator - .orchestrateStreamListenerSetupMethod(streamListener, method, bean); - } - - private Method checkProxy(Method methodArg, Object bean) { - Method method = methodArg; - if (AopUtils.isJdkDynamicProxy(bean)) { - try { - // Found a @StreamListener method on the target class for this JDK proxy - // -> - // is it also present on the proxy itself? - method = bean.getClass().getMethod(method.getName(), - method.getParameterTypes()); - Class[] proxiedInterfaces = ((Advised) bean).getProxiedInterfaces(); - for (Class iface : proxiedInterfaces) { - try { - method = iface.getMethod(method.getName(), - method.getParameterTypes()); - break; - } - catch (NoSuchMethodException noMethod) { - } - } - } - catch (SecurityException ex) { - ReflectionUtils.handleReflectionException(ex); - } - catch (NoSuchMethodException ex) { - throw new IllegalStateException(String.format( - "@StreamListener method '%s' found on bean target class '%s', " - + "but not found in any interface(s) for bean JDK proxy. Either " - + "pull the method up to an interface or switch to subclass (CGLIB) " - + "proxies by setting proxy-target-class/proxyTargetClass attribute to 'true'", - method.getName(), method.getDeclaringClass().getSimpleName()), - ex); - } - } - return method; - } - - private String resolveExpressionAsString(String value, String property) { - Object resolved = resolveExpression(value); - if (resolved instanceof String) { - return (String) resolved; - } - else { - throw new IllegalStateException("Resolved " + property + " to [" - + resolved.getClass() + "] instead of String for [" + value + "]"); - } - } - - private boolean resolveExpressionAsBoolean(String value, String property) { - Object resolved = resolveExpression(value); - if (resolved == null) { - return false; - } - else if (resolved instanceof String) { - return Boolean.parseBoolean((String) resolved); - } - else if (resolved instanceof Boolean) { - return (Boolean) resolved; - } - else { - throw new IllegalStateException( - "Resolved " + property + " to [" + resolved.getClass() - + "] instead of String or Boolean for [" + value + "]"); - } - } - - private String resolveExpression(String value) { - String resolvedValue = this.applicationContext.getBeanFactory() - .resolveEmbeddedValue(value); - if (resolvedValue.startsWith("#{") && value.endsWith("}")) { - resolvedValue = (String) this.resolver.evaluate(resolvedValue, - this.expressionContext); - } - return resolvedValue; - } - - /** - * This operations ensures that required dependencies are not accidentally injected - * early given that this bean is BPP. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void injectAndPostProcessDependencies() { - Collection streamListenerParameterAdapters = this.applicationContext - .getBeansOfType(StreamListenerParameterAdapter.class).values(); - Collection streamListenerResultAdapters = this.applicationContext - .getBeansOfType(StreamListenerResultAdapter.class).values(); - //this.binderAwareChannelResolver = this.applicationContext - // .getBean("binderAwareChannelResolver", DestinationResolver.class); - this.messageHandlerMethodFactory = this.applicationContext - .getBean("integrationMessageHandlerMethodFactory", MessageHandlerMethodFactory.class); - this.springIntegrationProperties = this.applicationContext - .getBean(SpringIntegrationProperties.class); - - this.streamListenerSetupMethodOrchestrators.addAll(this.applicationContext - .getBeansOfType(StreamListenerSetupMethodOrchestrator.class).values()); - - // Default orchestrator for StreamListener method invocation is added last into - // the LinkedHashSet. - this.streamListenerSetupMethodOrchestrators.add( - new DefaultStreamListenerSetupMethodOrchestrator(this.applicationContext, - streamListenerParameterAdapters, streamListenerResultAdapters)); - - this.streamListenerCallbacks.forEach(Runnable::run); - } - - private static class StreamListenerHandlerMethodMapping { - - private final Object targetBean; - - private final Method method; - - private final String condition; - - private final String defaultOutputChannel; - - private final String copyHeaders; - - StreamListenerHandlerMethodMapping(Object targetBean, Method method, - String condition, String defaultOutputChannel, String copyHeaders) { - this.targetBean = targetBean; - this.method = method; - this.condition = condition; - this.defaultOutputChannel = defaultOutputChannel; - this.copyHeaders = copyHeaders; - } - - Object getTargetBean() { - return this.targetBean; - } - - Method getMethod() { - return this.method; - } - - String getCondition() { - return this.condition; - } - - String getDefaultOutputChannel() { - return this.defaultOutputChannel; - } - - public String getCopyHeaders() { - return this.copyHeaders; - } - - } - - @SuppressWarnings("rawtypes") - private final class DefaultStreamListenerSetupMethodOrchestrator - implements StreamListenerSetupMethodOrchestrator { - - private final ConfigurableApplicationContext applicationContext; - - private final Collection streamListenerParameterAdapters; - - private final Collection streamListenerResultAdapters; - - private DefaultStreamListenerSetupMethodOrchestrator( - ConfigurableApplicationContext applicationContext, - Collection streamListenerParameterAdapters, - Collection streamListenerResultAdapters) { - this.applicationContext = applicationContext; - this.streamListenerParameterAdapters = streamListenerParameterAdapters; - this.streamListenerResultAdapters = streamListenerResultAdapters; - } - - @Override - public void orchestrateStreamListenerSetupMethod(StreamListener streamListener, - Method method, Object bean) { - String methodAnnotatedInboundName = streamListener.value(); - - String methodAnnotatedOutboundName = StreamListenerMethodUtils - .getOutboundBindingTargetName(method); - int inputAnnotationCount = StreamListenerMethodUtils - .inputAnnotationCount(method); - int outputAnnotationCount = StreamListenerMethodUtils - .outputAnnotationCount(method); - boolean isDeclarative = checkDeclarativeMethod(method, - methodAnnotatedInboundName, methodAnnotatedOutboundName); - StreamListenerMethodUtils.validateStreamListenerMethod(method, - inputAnnotationCount, outputAnnotationCount, - methodAnnotatedInboundName, methodAnnotatedOutboundName, - isDeclarative, streamListener.condition()); - if (isDeclarative) { - StreamListenerParameterAdapter[] toSlpaArray; - toSlpaArray = new StreamListenerParameterAdapter[this.streamListenerParameterAdapters - .size()]; - Object[] adaptedInboundArguments = adaptAndRetrieveInboundArguments( - method, methodAnnotatedInboundName, this.applicationContext, - this.streamListenerParameterAdapters.toArray(toSlpaArray)); - invokeStreamListenerResultAdapter(method, bean, - methodAnnotatedOutboundName, adaptedInboundArguments); - } - else { - registerHandlerMethodOnListenedChannel(method, streamListener, bean); - } - } - - @Override - public boolean supports(Method method) { - // default catch all orchestrator - return true; - } - - @SuppressWarnings("unchecked") - private void invokeStreamListenerResultAdapter(Method method, Object bean, - String outboundName, Object... arguments) { - try { - if (Void.TYPE.equals(method.getReturnType())) { - method.invoke(bean, arguments); - } - else { - Object result = method.invoke(bean, arguments); - if (!StringUtils.hasText(outboundName)) { - for (int parameterIndex = 0; parameterIndex < method - .getParameterCount(); parameterIndex++) { - MethodParameter methodParameter = MethodParameter - .forExecutable(method, parameterIndex); - if (methodParameter.hasParameterAnnotation(Output.class)) { - outboundName = methodParameter - .getParameterAnnotation(Output.class).value(); - } - } - } - Object targetBean = this.applicationContext.getBean(outboundName); - for (StreamListenerResultAdapter streamListenerResultAdapter : this.streamListenerResultAdapters) { - if (streamListenerResultAdapter.supports(result.getClass(), - targetBean.getClass())) { - streamListenerResultAdapter.adapt(result, targetBean); - break; - } - } - } - } - catch (Exception e) { - throw new BeanInitializationException( - "Cannot setup StreamListener for " + method, e); - } - } - - private void registerHandlerMethodOnListenedChannel(Method method, - StreamListener streamListener, Object bean) { - Assert.hasText(streamListener.value(), "The binding name cannot be null"); - if (!StringUtils.hasText(streamListener.value())) { - throw new BeanInitializationException( - "A bound component name must be specified"); - } - final String defaultOutputChannel = StreamListenerMethodUtils - .getOutboundBindingTargetName(method); - if (Void.TYPE.equals(method.getReturnType())) { - Assert.isTrue(StringUtils.isEmpty(defaultOutputChannel), - "An output channel cannot be specified for a method that does not return a value"); - } - else { - Assert.isTrue(!StringUtils.isEmpty(defaultOutputChannel), - "An output channel must be specified for a method that can return a value"); - } - StreamListenerMethodUtils.validateStreamListenerMessageHandler(method); - StreamListenerAnnotationBeanPostProcessor.this.mappedListenerMethods.add( - streamListener.value(), - new StreamListenerHandlerMethodMapping(bean, method, - streamListener.condition(), defaultOutputChannel, - streamListener.copyHeaders())); - } - - private boolean checkDeclarativeMethod(Method method, - String methodAnnotatedInboundName, String methodAnnotatedOutboundName) { - int methodArgumentsLength = method.getParameterCount(); - for (int parameterIndex = 0; parameterIndex < methodArgumentsLength; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - if (methodParameter.hasParameterAnnotation(Input.class)) { - String inboundName = (String) AnnotationUtils.getValue( - methodParameter.getParameterAnnotation(Input.class)); - Assert.isTrue(StringUtils.hasText(inboundName), - StreamListenerErrorMessages.INVALID_INBOUND_NAME); - Assert.isTrue( - isDeclarativeMethodParameter(inboundName, methodParameter), - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - return true; - } - else if (methodParameter.hasParameterAnnotation(Output.class)) { - String outboundName = (String) AnnotationUtils.getValue( - methodParameter.getParameterAnnotation(Output.class)); - Assert.isTrue(StringUtils.hasText(outboundName), - StreamListenerErrorMessages.INVALID_OUTBOUND_NAME); - Assert.isTrue( - isDeclarativeMethodParameter(outboundName, methodParameter), - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - return true; - } - else if (StringUtils.hasText(methodAnnotatedOutboundName)) { - return isDeclarativeMethodParameter(methodAnnotatedOutboundName, - methodParameter); - } - else if (StringUtils.hasText(methodAnnotatedInboundName)) { - return isDeclarativeMethodParameter(methodAnnotatedInboundName, - methodParameter); - } - } - return false; - } - - /** - * Determines if method parameters signify an imperative or declarative listener - * definition.
- * Imperative - where handler method is invoked on each message by the handler - * infrastructure provided by the framework
- * Declarative - where handler is provided by the method itself.
- * Declarative method parameter could either be {@link MessageChannel} or any - * other Object for which there is a {@link StreamListenerParameterAdapter} (i.e., - * {@link reactor.core.publisher.Flux}). Declarative method is invoked only once - * during initialization phase. - * @param targetBeanName name of the bean - * @param methodParameter method parameter - * @return {@code true} when the method parameter is declarative - */ - @SuppressWarnings("unchecked") - private boolean isDeclarativeMethodParameter(String targetBeanName, - MethodParameter methodParameter) { - boolean declarative = false; - if (!methodParameter.getParameterType().isAssignableFrom(Object.class) - && this.applicationContext.containsBean(targetBeanName)) { - declarative = MessageChannel.class - .isAssignableFrom(methodParameter.getParameterType()); - if (!declarative) { - Class targetBeanClass = this.applicationContext - .getType(targetBeanName); - declarative = this.streamListenerParameterAdapters.stream().anyMatch( - slpa -> slpa.supports(targetBeanClass, methodParameter)); - } - } - return declarative; - } - - } - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerErrorMessages.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerErrorMessages.java deleted file mode 100644 index cf1a19311..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerErrorMessages.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -/** - * @author Ilayaperumal Gopinathan - */ -public abstract class StreamListenerErrorMessages { - - /** - * Error message when the inbound name was invalid. - */ - public static final String INVALID_INBOUND_NAME = "The @Input annotation must have the name of an input as value"; - - /** - * Error message when the outbound name was invalid. - */ - public static final String INVALID_OUTBOUND_NAME = "The @Output annotation must have the name of an input as value"; - - /** - * Error message when there were no outputs specified. - */ - public static final String ATLEAST_ONE_OUTPUT = "At least one output must be specified"; - - /** - * Error message when multiple destinations were specified. - */ - public static final String SEND_TO_MULTIPLE_DESTINATIONS = "Multiple destinations cannot be specified"; - - /** - * Error message when empty destination was provided. - */ - public static final String SEND_TO_EMPTY_DESTINATION = "An empty destination cannot be specified"; - - /** - * Error message when the input or output annotation got placed on a method parameter. - */ - public static final String INVALID_INPUT_OUTPUT_METHOD_PARAMETERS = "@Input or @Output annotations " - + "are not permitted on " - + "method parameters while using the @StreamListener value and a method-level output specification"; - - /** - * Error message when no input destination was provided. - */ - public static final String NO_INPUT_DESTINATION = "No input destination is configured. " - + "Use either the @StreamListener value or @Input"; - - /** - * Error message when an ambiguous message handler method argument was found. - */ - public static final String AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS = "Ambiguous method arguments " - + "for the StreamListener method"; - - /** - * Error message when invalid input values where set. - */ - public static final String INVALID_INPUT_VALUES = "Cannot set both @StreamListener " - + "value and @Input annotation as method parameter"; - - /** - * Error message when invalid input value with output method parameter was set. - */ - public static final String INVALID_INPUT_VALUE_WITH_OUTPUT_METHOD_PARAM = "Setting the @StreamListener " - + "value when using @Output annotation as method parameter is not permitted. " - + "Use @Input method parameter annotation to specify inbound value instead"; - - /** - * Error message when invalid output values were set. - */ - public static final String INVALID_OUTPUT_VALUES = "Cannot set both output (@Output/@SendTo) method annotation value" - + " and @Output annotation as a method parameter"; - - /** - * Error message when condition was set in declarative mode. - */ - public static final String CONDITION_ON_DECLARATIVE_METHOD = "Cannot set a condition when " - + "using @StreamListener in declarative mode"; - - /** - * Error message when condition was set for methods that return a value. - */ - public static final String CONDITION_ON_METHOD_RETURNING_VALUE = "Cannot set a condition " - + "for methods that return a value"; - - /** - * Error message when multiple value returning methods were provided. - */ - public static final String MULTIPLE_VALUE_RETURNING_METHODS = "If multiple @StreamListener " - + "methods are listening to the same binding target, none of them may return a value"; - - private static final String PREFIX = "A method annotated with @StreamListener "; - - /** - * Error message when @StreamListener was used with @Input. - */ - public static final String INPUT_AT_STREAM_LISTENER = PREFIX - + "may never be annotated with @Input. " - + "If it should listen to a specific input, use the value of @StreamListener instead"; - - /** - * Error message when invalid input value with output method parameter was set. - */ - public static final String RETURN_TYPE_NO_OUTBOUND_SPECIFIED = PREFIX - + "having a return type should also have an outbound target specified"; - - /** - * Error message when return type was specified for multiple outbound targets. - */ - public static final String RETURN_TYPE_MULTIPLE_OUTBOUND_SPECIFIED = PREFIX - + "having a return type should have only one outbound target specified"; - - /** - * Error message when invalid declarative method parameters were set. - */ - public static final String INVALID_DECLARATIVE_METHOD_PARAMETERS = PREFIX - + "may use @Input or @Output annotations only in declarative mode " - + "and for parameters that are binding targets or convertible from binding targets."; - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMessageHandler.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMessageHandler.java deleted file mode 100644 index 4a311ce4a..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMessageHandler.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; - -/** - * @author Marius Bogoevici - * @author Gary Russell - * @since 1.2 - */ -public class StreamListenerMessageHandler extends AbstractReplyProducingMessageHandler { - - private final InvocableHandlerMethod invocableHandlerMethod; - - private final boolean copyHeaders; - - StreamListenerMessageHandler(InvocableHandlerMethod invocableHandlerMethod, - boolean copyHeaders, String[] notPropagatedHeaders) { - super(); - this.invocableHandlerMethod = invocableHandlerMethod; - this.copyHeaders = copyHeaders; - this.setNotPropagatedHeaders(notPropagatedHeaders); - } - - @Override - protected boolean shouldCopyRequestHeaders() { - return this.copyHeaders; - } - - public boolean isVoid() { - return this.invocableHandlerMethod.isVoid(); - } - - @Override - protected Object handleRequestMessage(Message requestMessage) { - try { - return this.invocableHandlerMethod.invoke(requestMessage); - } - catch (Exception e) { - if (e instanceof MessagingException) { - throw (MessagingException) e; - } - else { - throw new MessagingException(requestMessage, - "Exception thrown while invoking " - + this.invocableHandlerMethod.getShortLogMessage(), - e); - } - } - } - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMethodUtils.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMethodUtils.java deleted file mode 100644 index d61905941..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerMethodUtils.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.lang.reflect.Method; - -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * This class contains utility methods for handling {@link StreamListener} annotated bean - * methods. - * - * @author Ilayaperumal Gopinathan - */ -public final class StreamListenerMethodUtils { - - private StreamListenerMethodUtils() { - throw new IllegalStateException("Can't instantiate a utility class"); - } - - protected static int inputAnnotationCount(Method method) { - int inputAnnotationCount = 0; - for (int parameterIndex = 0; parameterIndex < method - .getParameterTypes().length; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - if (methodParameter.hasParameterAnnotation(Input.class)) { - inputAnnotationCount++; - } - } - return inputAnnotationCount; - } - - protected static int outputAnnotationCount(Method method) { - int outputAnnotationCount = 0; - for (int parameterIndex = 0; parameterIndex < method - .getParameterTypes().length; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - if (methodParameter.hasParameterAnnotation(Output.class)) { - outputAnnotationCount++; - } - } - return outputAnnotationCount; - } - - protected static void validateStreamListenerMethod(Method method, - int inputAnnotationCount, int outputAnnotationCount, - String methodAnnotatedInboundName, String methodAnnotatedOutboundName, - boolean isDeclarative, String condition) { - int methodArgumentsLength = method.getParameterTypes().length; - if (!isDeclarative) { - Assert.isTrue(inputAnnotationCount == 0 && outputAnnotationCount == 0, - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - if (StringUtils.hasText(methodAnnotatedInboundName) - && StringUtils.hasText(methodAnnotatedOutboundName)) { - Assert.isTrue(inputAnnotationCount == 0 && outputAnnotationCount == 0, - StreamListenerErrorMessages.INVALID_INPUT_OUTPUT_METHOD_PARAMETERS); - } - if (StringUtils.hasText(methodAnnotatedInboundName)) { - Assert.isTrue(inputAnnotationCount == 0, - StreamListenerErrorMessages.INVALID_INPUT_VALUES); - Assert.isTrue(outputAnnotationCount == 0, - StreamListenerErrorMessages.INVALID_INPUT_VALUE_WITH_OUTPUT_METHOD_PARAM); - } - else { - Assert.isTrue(inputAnnotationCount >= 1, - StreamListenerErrorMessages.NO_INPUT_DESTINATION); - } - if (StringUtils.hasText(methodAnnotatedOutboundName)) { - Assert.isTrue(outputAnnotationCount == 0, - StreamListenerErrorMessages.INVALID_OUTPUT_VALUES); - } - if (!Void.TYPE.equals(method.getReturnType())) { - Assert.isTrue(!StringUtils.hasText(condition), - StreamListenerErrorMessages.CONDITION_ON_METHOD_RETURNING_VALUE); - } - if (isDeclarative) { - Assert.isTrue(!StringUtils.hasText(condition), - StreamListenerErrorMessages.CONDITION_ON_DECLARATIVE_METHOD); - for (int parameterIndex = 0; parameterIndex < methodArgumentsLength; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - if (methodParameter.hasParameterAnnotation(Input.class)) { - String inboundName = (String) AnnotationUtils.getValue( - methodParameter.getParameterAnnotation(Input.class)); - Assert.isTrue(StringUtils.hasText(inboundName), - StreamListenerErrorMessages.INVALID_INBOUND_NAME); - } - if (methodParameter.hasParameterAnnotation(Output.class)) { - String outboundName = (String) AnnotationUtils.getValue( - methodParameter.getParameterAnnotation(Output.class)); - Assert.isTrue(StringUtils.hasText(outboundName), - StreamListenerErrorMessages.INVALID_OUTBOUND_NAME); - } - } - if (methodArgumentsLength > 1) { - Assert.isTrue( - inputAnnotationCount - + outputAnnotationCount == methodArgumentsLength, - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - - if (!method.getReturnType().equals(Void.TYPE)) { - if (!StringUtils.hasText(methodAnnotatedOutboundName)) { - if (outputAnnotationCount == 0) { - throw new IllegalArgumentException( - StreamListenerErrorMessages.RETURN_TYPE_NO_OUTBOUND_SPECIFIED); - } - Assert.isTrue((outputAnnotationCount == 1), - StreamListenerErrorMessages.RETURN_TYPE_MULTIPLE_OUTBOUND_SPECIFIED); - } - } - } - - protected static void validateStreamListenerMessageHandler(Method method) { - int methodArgumentsLength = method.getParameterTypes().length; - if (methodArgumentsLength > 1) { - int numAnnotatedMethodParameters = 0; - int numPayloadAnnotations = 0; - for (int parameterIndex = 0; parameterIndex < methodArgumentsLength; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - if (methodParameter.hasParameterAnnotations()) { - numAnnotatedMethodParameters++; - } - if (methodParameter.hasParameterAnnotation(Payload.class)) { - numPayloadAnnotations++; - } - } - if (numPayloadAnnotations > 0) { - Assert.isTrue( - methodArgumentsLength == numAnnotatedMethodParameters - && numPayloadAnnotations <= 1, - StreamListenerErrorMessages.AMBIGUOUS_MESSAGE_HANDLER_METHOD_ARGUMENTS); - } - } - } - - protected static String getOutboundBindingTargetName(Method method) { - SendTo sendTo = AnnotationUtils.findAnnotation(method, SendTo.class); - if (sendTo != null) { - Assert.isTrue(!ObjectUtils.isEmpty(sendTo.value()), - StreamListenerErrorMessages.ATLEAST_ONE_OUTPUT); - Assert.isTrue(sendTo.value().length == 1, - StreamListenerErrorMessages.SEND_TO_MULTIPLE_DESTINATIONS); - Assert.hasText(sendTo.value()[0], - StreamListenerErrorMessages.SEND_TO_EMPTY_DESTINATION); - return sendTo.value()[0]; - } - Output output = AnnotationUtils.findAnnotation(method, Output.class); - if (output != null) { - Assert.isTrue(StringUtils.hasText(output.value()), - StreamListenerErrorMessages.ATLEAST_ONE_OUTPUT); - return output.value(); - } - return null; - } - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerParameterAdapter.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerParameterAdapter.java deleted file mode 100644 index 7d7ebf784..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerParameterAdapter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import org.springframework.core.MethodParameter; - -/** - * Strategy for adapting a method argument type annotated with - * {@link org.springframework.cloud.stream.annotation.Input} or - * {@link org.springframework.cloud.stream.annotation.Output} from a binding type (e.g. - * {@link org.springframework.messaging.MessageChannel}) supported by an existing binder. - * - * This is a framework extension and is not primarily intended for use by end-users. - * - * @param adapter type - * @param binding result type - * @author Marius Bogoevici - */ -public interface StreamListenerParameterAdapter { - - /** - * Return true if the conversion from the binding target type to the argument type is - * supported. - * @param bindingTargetType the binding target type - * @param methodParameter the method parameter for which the conversion is performed - * @return true if the conversion is supported - */ - boolean supports(Class bindingTargetType, MethodParameter methodParameter); - - /** - * Adapts the binding target to the argument type. The result will be passed as - * argument to a method annotated with - * {@link org.springframework.cloud.stream.annotation.StreamListener} when used for - * setting up a pipeline. - * @param bindingTarget the binding target - * @param parameter the method parameter for which the conversion is performed - * @return an instance of the parameter type, which will be passed to the method - */ - A adapt(B bindingTarget, MethodParameter parameter); - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerResultAdapter.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerResultAdapter.java deleted file mode 100644 index 6724a5263..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerResultAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2016-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.io.Closeable; - -/** - * A strategy for adapting the result of a - * {@link org.springframework.cloud.stream.annotation.StreamListener} annotated method to - * a binding target annotated with - * {@link org.springframework.cloud.stream.annotation.Output}. - * - * Used when the {@link org.springframework.cloud.stream.annotation.StreamListener} - * annotated method is operating in declarative mode. - * - * @param stream listener result type - * @param binding target type - * @author Marius Bogoevici - */ -public interface StreamListenerResultAdapter { - - /** - * Return true if the result type can be converted to the binding target. - * @param resultType the result type. - * @param bindingTarget the binding target. - * @return true if the conversion can take place. - */ - boolean supports(Class resultType, Class bindingTarget); - - /** - * Adapts the result to the binding target. - * @param streamListenerResult the result of invoking the method. - * @param bindingTarget the binding target. - * @return an adapted result - */ - Closeable adapt(R streamListenerResult, B bindingTarget); - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerSetupMethodOrchestrator.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerSetupMethodOrchestrator.java deleted file mode 100644 index e1fe39af8..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binding/StreamListenerSetupMethodOrchestrator.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2018-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binding; - -import java.lang.reflect.Method; - -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.Output; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.context.ApplicationContext; -import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Orchestrator used for invoking the {@link StreamListener} setup method. - * - * By default {@link StreamListenerAnnotationBeanPostProcessor} will use an internal - * implementation of this interface to invoke {@link StreamListenerParameterAdapter}s and - * {@link StreamListenerResultAdapter}s or handler mappings on the method annotated with - * {@link StreamListener}. - * - * By providing a different implementation of this interface and registering it as a - * Spring Bean in the context, one can override the default invocation strategies used by - * the {@link StreamListenerAnnotationBeanPostProcessor}. A typical usecase for such - * overriding can happen when a downstream - * {@link org.springframework.cloud.stream.binder.Binder} implementation wants to change - * the way in which any of the default StreamListener handling needs to be changed in a - * custom manner. - * - * When beans of this interface are present in the context, they get priority in the - * {@link StreamListenerAnnotationBeanPostProcessor} before falling back to the default - * implementation. - * - * @author Soby Chacko - * @see StreamListener - * @see StreamListenerAnnotationBeanPostProcessor - */ -public interface StreamListenerSetupMethodOrchestrator { - - /** - * Checks the method annotated with {@link StreamListener} to see if this - * implementation can successfully orchestrate this method. - * @param method annotated with {@link StreamListener} - * @return true if this implementation can orchestrate this method, false otherwise - */ - boolean supports(Method method); - - /** - * Method that allows custom orchestration on the {@link StreamListener} setup method. - * @param streamListener reference to the {@link StreamListener} annotation on the - * method - * @param method annotated with {@link StreamListener} - * @param bean that contains the StreamListener method - * - */ - void orchestrateStreamListenerSetupMethod(StreamListener streamListener, - Method method, Object bean); - - /** - * Default implementation for adapting each of the incoming method arguments using an - * available {@link StreamListenerParameterAdapter} and provide the adapted collection - * of arguments back to the caller. - * @param method annotated with {@link StreamListener} - * @param inboundName inbound binding - * @param applicationContext spring application context - * @param streamListenerParameterAdapters used for adapting the method arguments - * @return adapted incoming arguments - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - default Object[] adaptAndRetrieveInboundArguments(Method method, String inboundName, - ApplicationContext applicationContext, - StreamListenerParameterAdapter... streamListenerParameterAdapters) { - Object[] arguments = new Object[method.getParameterTypes().length]; - for (int parameterIndex = 0; parameterIndex < arguments.length; parameterIndex++) { - MethodParameter methodParameter = MethodParameter.forExecutable(method, - parameterIndex); - Class parameterType = methodParameter.getParameterType(); - Object targetReferenceValue = null; - if (methodParameter.hasParameterAnnotation(Input.class)) { - targetReferenceValue = AnnotationUtils - .getValue(methodParameter.getParameterAnnotation(Input.class)); - } - else if (methodParameter.hasParameterAnnotation(Output.class)) { - targetReferenceValue = AnnotationUtils - .getValue(methodParameter.getParameterAnnotation(Output.class)); - } - else if (arguments.length == 1 && StringUtils.hasText(inboundName)) { - targetReferenceValue = inboundName; - } - if (targetReferenceValue != null) { - Assert.isInstanceOf(String.class, targetReferenceValue, - "Annotation value must be a String"); - Object targetBean = applicationContext - .getBean((String) targetReferenceValue); - // Iterate existing parameter adapters first - for (StreamListenerParameterAdapter streamListenerParameterAdapter : streamListenerParameterAdapters) { - if (streamListenerParameterAdapter.supports(targetBean.getClass(), - methodParameter)) { - arguments[parameterIndex] = streamListenerParameterAdapter - .adapt(targetBean, methodParameter); - break; - } - } - if (arguments[parameterIndex] == null - && parameterType.isAssignableFrom(targetBean.getClass())) { - arguments[parameterIndex] = targetBean; - } - Assert.notNull(arguments[parameterIndex], - "Cannot convert argument " + parameterIndex + " of " + method - + "from " + targetBean.getClass() + " to " - + parameterType); - } - else { - throw new IllegalStateException( - StreamListenerErrorMessages.INVALID_DECLARATIVE_METHOD_PARAMETERS); - } - } - return arguments; - } - -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java index 8bb16c341..f6fb6ef7d 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java @@ -49,9 +49,7 @@ import org.springframework.cloud.stream.binding.BindingsLifecycleController; import org.springframework.cloud.stream.binding.ContextStartAfterRefreshListener; import org.springframework.cloud.stream.binding.DynamicDestinationsBindable; import org.springframework.cloud.stream.binding.InputBindingLifecycle; -import org.springframework.cloud.stream.binding.MessageChannelStreamListenerResultAdapter; import org.springframework.cloud.stream.binding.OutputBindingLifecycle; -import org.springframework.cloud.stream.binding.StreamListenerAnnotationBeanPostProcessor; import org.springframework.cloud.stream.config.BindingHandlerAdvise.MappingsProvider; import org.springframework.cloud.stream.function.StreamFunctionProperties; import org.springframework.cloud.stream.micrometer.DestinationPublishingMetricsAutoConfiguration; @@ -175,12 +173,6 @@ public class BindingServiceConfiguration { }; } - @Bean(name = STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME) - @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) - public static StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor() { - return new StreamListenerAnnotationBeanPostProcessor(); - } - @Bean public BindingHandlerAdvise BindingHandlerAdvise( @Nullable MappingsProvider[] providers) { @@ -207,11 +199,6 @@ public class BindingServiceConfiguration { return binderFactory; } - @Bean - public MessageChannelStreamListenerResultAdapter messageChannelStreamListenerResultAdapter() { - return new MessageChannelStreamListenerResultAdapter(); - } - @Bean // This conditional is intentionally not in an autoconfig (usually a bad idea) because // it is used to detect a BindingService in the parent context (which we know diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/ErrorBindingTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/ErrorBindingTests.java index 6846ff1fc..303ba97e9 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/ErrorBindingTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/ErrorBindingTests.java @@ -16,6 +16,9 @@ package org.springframework.cloud.stream.binder; +import java.util.function.Consumer; +import java.util.function.Function; + import org.junit.Test; import org.mockito.Mockito; @@ -23,14 +26,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.cloud.stream.binder.test.InputDestination; import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.cloud.stream.messaging.Sink; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; @@ -58,9 +58,9 @@ public class ErrorBindingTests { Binder binder = binderFactory.getBinder(null, MessageChannel.class); - Mockito.verify(binder).bindConsumer(eq("input"), isNull(), + Mockito.verify(binder).bindConsumer(eq("processor-in-0"), isNull(), any(MessageChannel.class), any(ConsumerProperties.class)); - Mockito.verify(binder).bindProducer(eq("output"), any(MessageChannel.class), + Mockito.verify(binder).bindProducer(eq("processor-out-0"), any(MessageChannel.class), any(ProducerProperties.class)); Mockito.verifyNoMoreInteractions(binder); applicationContext.close(); @@ -72,7 +72,7 @@ public class ErrorBindingTests { TestChannelBinderConfiguration.getCompleteConfiguration( ErrorBindingTests.ErrorConfigurationDefault.class)) .web(WebApplicationType.NONE) - .run("--spring.cloud.stream.bindings.input.consumer.max-attempts=1", + .run("--spring.cloud.stream.bindings.handle-in-0.consumer.max-attempts=1", "--spring.jmx.enabled=false"); InputDestination source = context.getBean(InputDestination.class); @@ -91,7 +91,7 @@ public class ErrorBindingTests { TestChannelBinderConfiguration.getCompleteConfiguration( ErrorBindingTests.ErrorConfigurationWithCustomErrorHandler.class)) .web(WebApplicationType.NONE) - .run("--spring.cloud.stream.bindings.input.consumer.max-attempts=1", + .run("--spring.cloud.stream.bindings.handle-in-0.consumer.max-attempts=1", "--spring.jmx.enabled=false"); InputDestination source = context.getBean(InputDestination.class); @@ -104,36 +104,41 @@ public class ErrorBindingTests { assertThat(errorConfiguration.counter == 6); } - @EnableBinding(Processor.class) @EnableAutoConfiguration public static class TestProcessor { + @Bean + public Function processor() { + return s -> s; + } } - @EnableBinding(Processor.class) @EnableAutoConfiguration public static class ErrorConfigurationDefault { private int counter; - @StreamListener(Sink.INPUT) - public void handle(Object value) { - this.counter++; - throw new RuntimeException("BOOM!"); + @Bean + public Consumer handle() { + return v -> { + this.counter++; + throw new RuntimeException("BOOM!"); + }; } } - @EnableBinding(Processor.class) @EnableAutoConfiguration public static class ErrorConfigurationWithCustomErrorHandler { private int counter; - @StreamListener(Sink.INPUT) - public void handle(Object value) { - this.counter++; - throw new RuntimeException("BOOM!"); + @Bean + public Consumer handle() { + return v -> { + this.counter++; + throw new RuntimeException("BOOM!"); + }; } @ServiceActivator(inputChannel = "input.anonymous.errors") diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java deleted file mode 100644 index d6644ea35..000000000 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * Copyright 2017-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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder.tck; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Ignore; -import org.junit.Test; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binder.test.InputDestination; -import org.springframework.cloud.stream.binder.test.OutputDestination; -import org.springframework.cloud.stream.binder.test.TestChannelBinder; -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.lang.Nullable; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.MessagingException; -import org.springframework.messaging.converter.AbstractMessageConverter; -import org.springframework.messaging.converter.MessageConversionException; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.util.MimeType; -import org.springframework.util.MimeTypeUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Sort of a TCK test suite to validate payload conversion is done properly by interacting - * with binder's input/output destinations instead of its bridged channels. This means - * that all payloads (sent/received) must be expressed in the wire format (byte[]) - * - * @author Oleg Zhurakousky - * @author Gary Russell - * - */ -public class ContentTypeTckTests { - - @Test - public void stringToMapStreamListener() { - ApplicationContext context = new SpringApplicationBuilder( - StringToMapStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload())).isEqualTo("oleg"); - } - - @Test - public void stringToMapMessageStreamListener() { - ApplicationContext context = new SpringApplicationBuilder( - StringToMapMessageStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload())).isEqualTo("oleg"); - } - - @Test - public void withInternalPipeline() { - ApplicationContext context = new SpringApplicationBuilder(InternalPipeLine.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload())).isEqualTo("OLEG"); - } - - @Test - public void pojoToPojo() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void pojoToString() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToStringStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void pojoToStringOutboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToStringStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.TEXT_PLAIN); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void pojoToByteArray() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToByteArrayStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void pojoToByteArrayOutboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToByteArrayStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void stringToPojoInboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - StringToPojoStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessToPojoInboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessToPojoStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessToPojoInboundContentTypeBindingJson() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessToPojoStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.input.contentType=application/json", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessMessageToPojoInboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessMessageToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessMessageToPojoInboundContentTypeBindingJson() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessMessageToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.cloud.stream.bindings.input.contentType=application/json", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessToPojoWithTextHeaderContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeType.valueOf("text/plain")) - .build()); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void typelessToPojoOutboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessToMessageStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) - .setHeader("contentType", new MimeType("text", "plain")).build()); - - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.TEXT_PLAIN); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void outboundMessageWithTextContentTypeOnly() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessToMessageTextOnlyContentTypeStreamListener.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) - .setHeader("contentType", new MimeType("text")).build()); - - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE).toString()) - .isEqualTo("text/plain"); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void stringToPojoInboundContentTypeHeader() { - ApplicationContext context = new SpringApplicationBuilder( - StringToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes(), - new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.TEXT_PLAIN)))); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void byteArrayToPojoInboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - ByteArrayToPojoStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void byteArrayToPojoInboundContentTypeHeader() { - ApplicationContext context = new SpringApplicationBuilder( - StringToPojoStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes(), - new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.TEXT_PLAIN)))); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void byteArrayToByteArray() { - ApplicationContext context = new SpringApplicationBuilder( - ByteArrayToByteArrayStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void byteArrayToByteArrayInboundOutboundContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - ByteArrayToByteArrayStreamListener.class).web(WebApplicationType.NONE) - .run("--spring.cloud.stream.bindings.input.contentType=text/plain", - "--spring.cloud.stream.bindings.output.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void pojoMessageToStringMessage() { - ApplicationContext context = new SpringApplicationBuilder( - PojoMessageToStringMessageStreamListener.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.TEXT_PLAIN); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void pojoMessageToStringMessageServiceActivator() { - ApplicationContext context = new SpringApplicationBuilder( - PojoMessageToStringMessageServiceActivator.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.TEXT_PLAIN); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void byteArrayMessageToStringJsonMessageStreamListener() { - ApplicationContext context = new SpringApplicationBuilder( - ByteArrayMessageToStringJsonMessageStreamListener.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.APPLICATION_JSON); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("{\"name\":\"bob\"}"); - } - - @Test - public void byteArrayMessageToStringMessageStreamListener() { - ApplicationContext context = new SpringApplicationBuilder( - StringMessageToStringMessageStreamListener.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeTypeUtils.TEXT_PLAIN); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("oleg"); - } - - @Test - public void customMessageConverter_defaultContentTypeBinding() { - ApplicationContext context = new SpringApplicationBuilder( - StringToStringStreamListener.class, CustomConverters.class) - .web(WebApplicationType.NONE) - .run("--spring.cloud.stream.default.contentType=foo/bar", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage).isNotNull(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("FooBarMessageConverter"); - assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MimeType.valueOf("foo/bar")); - } - - // Failure tests - - @Test - public void _jsonToPojoWrongDefaultContentTypeProperty() { - ApplicationContext context = new SpringApplicationBuilder( - PojoToPojoStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.default.contentType=text/plain", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - TestChannelBinder binder = context.getBean(TestChannelBinder.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - assertThat(binder.getLastError().getPayload() instanceof MessagingException) - .isTrue(); - } - - @Test - @Ignore - public void _toStringDefaultContentTypePropertyUnknownContentType() { - ApplicationContext context = new SpringApplicationBuilder( - StringToStringStreamListener.class).web(WebApplicationType.NONE).run( - "--spring.cloud.stream.default.contentType=foo/bar", - "--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - TestChannelBinder binder = context.getBean(TestChannelBinder.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - assertThat( - binder.getLastError().getPayload() instanceof MessageConversionException) - .isTrue(); - } - - @Test - public void toCollectionWithParameterizedType() { - ApplicationContext context = new SpringApplicationBuilder( - CollectionWithParameterizedTypes.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "[{\"person\":{\"name\":\"jon\"},\"id\":123},{\"person\":{\"name\":\"jane\"},\"id\":456}]"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(outputMessage.getPayload()).isEqualTo(jsonPayload.getBytes()); - } - - // ====== - @Test - public void testWithMapInputParameter() { - ApplicationContext context = new SpringApplicationBuilder( - MapInputConfiguration.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void testWithMapPayloadParameter() { - ApplicationContext context = new SpringApplicationBuilder( - MapInputConfiguration.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void testWithListInputParameter() { - ApplicationContext context = new SpringApplicationBuilder( - ListInputConfiguration.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "[\"foo\",\"bar\"]"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void testWithMessageHeadersInputParameter() { - ApplicationContext context = new SpringApplicationBuilder( - MessageHeadersInputConfiguration.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "{\"name\":\"oleg\"}"; - source.send(new GenericMessage<>(jsonPayload.getBytes())); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isNotEqualTo(jsonPayload); - assertThat(outputMessage.getHeaders().containsKey(MessageHeaders.ID)).isTrue(); - assertThat(outputMessage.getHeaders().containsKey(MessageHeaders.CONTENT_TYPE)) - .isTrue(); - } - - @Test - public void testWithTypelessInputParameterAndOctetStream() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessPayloadConfiguration.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "[\"foo\",\"bar\"]"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) - .setHeader(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.APPLICATION_OCTET_STREAM) - .build()); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void testWithTypelessInputParameterAndServiceActivator() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessPayloadConfigurationSA.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "[\"foo\",\"bar\"]"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()).build()); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @Test - public void testWithTypelessMessageInputParameterAndServiceActivator() { - ApplicationContext context = new SpringApplicationBuilder( - TypelessMessageConfigurationSA.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - String jsonPayload = "[\"foo\",\"bar\"]"; - source.send(MessageBuilder.withPayload(jsonPayload.getBytes()).build()); - Message outputMessage = target.receive(); - assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo(jsonPayload); - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class CollectionWithParameterizedTypes { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public List> echo(List> value) { - assertThat(value.get(0) != null).isTrue(); - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TextInJsonOutListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Message echo(String value) { - return MessageBuilder.withPayload(value).setHeader( - MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class PojoToPojoStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Person echo(Person value) { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class PojoToStringStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String echo(Person value) { - return value.toString(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class PojoToByteArrayStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public byte[] echo(Person value) { - return value.toString().getBytes(StandardCharsets.UTF_8); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class ByteArrayToPojoStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Person echo(byte[] value) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(value, Person.class); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class StringToPojoStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Person echo(String value) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(value, Person.class); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessToPojoStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Person echo(Object value) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - // assume it is string because CT is text/plain - return value instanceof byte[] - ? mapper.readValue((byte[]) value, Person.class) - : mapper.readValue((String) value, Person.class); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessMessageToPojoStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Person echo(Message message) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - // assume it is string because CT is text/plain - return message.getPayload() instanceof byte[] - ? mapper.readValue((byte[]) message.getPayload(), Person.class) - : mapper.readValue((String) message.getPayload(), Person.class); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessToMessageStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Message echo(Object value) throws Exception { - return MessageBuilder.withPayload(value.toString()) - .setHeader("contentType", new MimeType("text", "plain")).build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessToMessageTextOnlyContentTypeStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Message echo(Object value) throws Exception { - return MessageBuilder.withPayload(value.toString()) - .setHeader("contentType", new MimeType("text")).build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class ByteArrayToByteArrayStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public byte[] echo(byte[] value) { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class StringToStringStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String echo(String value) { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - /* - * Uncomment to test MBean name quoting for ":" in bean name component of ObjectName. - * Commented to avoid "InstanceAlreadyExistsException" in other tests. - */ - // @EnableIntegrationMBeanExport - public static class StringToMapStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String echo(@Payload Map value) { - return (String) value.get("name"); - } - - @ServiceActivator(inputChannel = "input:foo.myGroup.errors") - public void error(Message message) { - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class StringToMapMessageStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String echo(Message> value) { - assertThat(value.getPayload() instanceof Map).isTrue(); - return (String) value.getPayload().get("name"); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class PojoMessageToStringMessageStreamListener { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Message echo(Message value) { - return MessageBuilder.withPayload(value.getPayload().toString()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) - .build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class PojoMessageToStringMessageServiceActivator { - - @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) - public Message echo(Message value) { - return MessageBuilder.withPayload(value.getPayload().toString()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) - .build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class StringMessageToStringMessageStreamListener { - - @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) - public Message echo(Message value) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - Person person = mapper.readValue(value.getPayload(), Person.class); - return MessageBuilder.withPayload(person.toString()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) - .build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class ByteArrayMessageToStringJsonMessageStreamListener { - - @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) - public Message echo(Message value) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - Person person = mapper.readValue(value.getPayload(), Person.class); - person.setName("bob"); - String json = mapper.writeValueAsString(person); - return MessageBuilder.withPayload(json).build(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class InternalPipeLine { - - @StreamListener(Processor.INPUT) - @SendTo("internalChannel") - public String handleA(Person value) { - return "{\"name\":\"" + value.getName().toUpperCase() + "\"}"; - } - - @Bean - public MessageChannel internalChannel() { - return new DirectChannel(); - } - - @StreamListener("internalChannel") - @SendTo(Processor.OUTPUT) - public String handleB(Person value) { - return value.toString(); - } - - } - - public static class Employee

{ - - private P person; - - private int id; - - public int getId() { - return this.id; - } - - public void setId(int id) { - this.id = id; - } - - public P getPerson() { - return this.person; - } - - public void setPerson(P person) { - this.person = person; - } - - } - - public static class Person { - - private String name; - - public Person() { - this(null); - } - - public Person(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return this.name; - } - - } - - @Configuration - public static class CustomConverters { - - @Bean - public FooBarMessageConverter fooBarMessageConverter() { - return new FooBarMessageConverter(MimeType.valueOf("foo/bar")); - } - - @Bean - public AlwaysStringKryoMessageConverter kryoOverrideMessageConverter() { - return new AlwaysStringKryoMessageConverter( - MimeType.valueOf("application/x-java-object")); - } - - /** - * Even though this MessageConverter has nothing to do with Kryo it still shows - * how Kryo conversion can be customized/overriden since it simply overriding a - * converter for contentType 'application/x-java-object'. - * - */ - public static class AlwaysStringKryoMessageConverter - extends AbstractMessageConverter { - - public AlwaysStringKryoMessageConverter(MimeType supportedMimeType) { - super(supportedMimeType); - } - - @Override - protected boolean supports(Class clazz) { - return clazz == null || String.class.isAssignableFrom(clazz); - } - - @Override - protected Object convertFromInternal(Message message, Class targetClass, - @Nullable Object conversionHint) { - return this.getClass().getSimpleName(); - } - - @Override - protected Object convertToInternal(Object payload, - @Nullable MessageHeaders headers, @Nullable Object conversionHint) { - return ((String) payload).getBytes(StandardCharsets.UTF_8); - } - - } - - public static class FooBarMessageConverter extends AbstractMessageConverter { - - protected FooBarMessageConverter(MimeType supportedMimeType) { - super(supportedMimeType); - } - - @Override - protected boolean supports(Class clazz) { - return clazz != null && String.class.isAssignableFrom(clazz); - } - - @Override - protected Object convertFromInternal(Message message, Class targetClass, - @Nullable Object conversionHint) { - return this.getClass().getSimpleName(); - } - - @Override - protected Object convertToInternal(Object payload, - @Nullable MessageHeaders headers, @Nullable Object conversionHint) { - return ((String) payload).getBytes(StandardCharsets.UTF_8); - } - - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class MapInputConfiguration { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Map echo(Map value) throws Exception { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class MapPayloadConfiguration { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Map echo(Message> value) throws Exception { - return value.getPayload(); - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class ListInputConfiguration { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public List echo(List value) throws Exception { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class MessageHeadersInputConfiguration { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Map echo(MessageHeaders value) throws Exception { - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessPayloadConfiguration { - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public Object echo(Object value) throws Exception { - System.out.println(value); - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessPayloadConfigurationSA { - - @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) - public Object echo(Object value) throws Exception { - System.out.println(value); - return value; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class TypelessMessageConfigurationSA { - - @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) - public Object echo(Message value) throws Exception { - System.out.println(value.getPayload()); - return value.getPayload(); - } - - } - -} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java.todo b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java.todo new file mode 100644 index 000000000..2edf3f3f0 --- /dev/null +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java.todo @@ -0,0 +1,1163 @@ +///* +// * Copyright 2017-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. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.springframework.cloud.stream.binder.tck; +// +//import java.nio.charset.StandardCharsets; +//import java.util.Collections; +//import java.util.List; +//import java.util.Map; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import org.junit.Ignore; +//import org.junit.Test; +// +//import org.springframework.boot.WebApplicationType; +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +//import org.springframework.boot.builder.SpringApplicationBuilder; +//import org.springframework.cloud.stream.annotation.EnableBinding; +//import org.springframework.cloud.stream.annotation.StreamListener; +//import org.springframework.cloud.stream.binder.test.InputDestination; +//import org.springframework.cloud.stream.binder.test.OutputDestination; +//import org.springframework.cloud.stream.binder.test.TestChannelBinder; +//import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; +//import org.springframework.cloud.stream.messaging.Processor; +//import org.springframework.context.ApplicationContext; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Import; +//import org.springframework.integration.annotation.ServiceActivator; +//import org.springframework.integration.channel.DirectChannel; +//import org.springframework.lang.Nullable; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.MessageChannel; +//import org.springframework.messaging.MessageHeaders; +//import org.springframework.messaging.MessagingException; +//import org.springframework.messaging.converter.AbstractMessageConverter; +//import org.springframework.messaging.converter.MessageConversionException; +//import org.springframework.messaging.handler.annotation.Payload; +//import org.springframework.messaging.handler.annotation.SendTo; +//import org.springframework.messaging.support.GenericMessage; +//import org.springframework.messaging.support.MessageBuilder; +//import org.springframework.util.MimeType; +//import org.springframework.util.MimeTypeUtils; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +///** +// * Sort of a TCK test suite to validate payload conversion is done properly by interacting +// * with binder's input/output destinations instead of its bridged channels. This means +// * that all payloads (sent/received) must be expressed in the wire format (byte[]) +// * +// * @author Oleg Zhurakousky +// * @author Gary Russell +// * +// */ +//public class ContentTypeTckTests { +// +// @Test +// public void stringToMapStreamListener() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToMapStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload())).isEqualTo("oleg"); +// } +// +// @Test +// public void stringToMapMessageStreamListener() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToMapMessageStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload())).isEqualTo("oleg"); +// } +// +// @Test +// public void withInternalPipeline() { +// ApplicationContext context = new SpringApplicationBuilder(InternalPipeLine.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload())).isEqualTo("OLEG"); +// } +// +// @Test +// public void pojoToPojo() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void pojoToString() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToStringStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void pojoToStringOutboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToStringStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.output.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.TEXT_PLAIN); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void pojoToByteArray() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToByteArrayStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void pojoToByteArrayOutboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToByteArrayStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.output.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void stringToPojoInboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToPojoStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.input.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessToPojoInboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessToPojoStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.input.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessToPojoInboundContentTypeBindingJson() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessToPojoStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.input.contentType=application/json", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessMessageToPojoInboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessMessageToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.cloud.stream.bindings.input.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessMessageToPojoInboundContentTypeBindingJson() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessMessageToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.cloud.stream.bindings.input.contentType=application/json", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessToPojoWithTextHeaderContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeType.valueOf("text/plain")) +// .build()); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void typelessToPojoOutboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessToMessageStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.output.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) +// .setHeader("contentType", new MimeType("text", "plain")).build()); +// +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.TEXT_PLAIN); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void outboundMessageWithTextContentTypeOnly() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessToMessageTextOnlyContentTypeStreamListener.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) +// .setHeader("contentType", new MimeType("text")).build()); +// +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE).toString()) +// .isEqualTo("text/plain"); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void stringToPojoInboundContentTypeHeader() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes(), +// new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, +// MimeTypeUtils.TEXT_PLAIN)))); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void byteArrayToPojoInboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// ByteArrayToPojoStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.bindings.input.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void byteArrayToPojoInboundContentTypeHeader() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToPojoStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes(), +// new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, +// MimeTypeUtils.TEXT_PLAIN)))); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void byteArrayToByteArray() { +// ApplicationContext context = new SpringApplicationBuilder( +// ByteArrayToByteArrayStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void byteArrayToByteArrayInboundOutboundContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// ByteArrayToByteArrayStreamListener.class).web(WebApplicationType.NONE) +// .run("--spring.cloud.stream.bindings.input.contentType=text/plain", +// "--spring.cloud.stream.bindings.output.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void pojoMessageToStringMessage() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoMessageToStringMessageStreamListener.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.TEXT_PLAIN); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void pojoMessageToStringMessageServiceActivator() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoMessageToStringMessageServiceActivator.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.TEXT_PLAIN); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void byteArrayMessageToStringJsonMessageStreamListener() { +// ApplicationContext context = new SpringApplicationBuilder( +// ByteArrayMessageToStringJsonMessageStreamListener.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.APPLICATION_JSON); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("{\"name\":\"bob\"}"); +// } +// +// @Test +// public void byteArrayMessageToStringMessageStreamListener() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringMessageToStringMessageStreamListener.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeTypeUtils.TEXT_PLAIN); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("oleg"); +// } +// +// @Test +// public void customMessageConverter_defaultContentTypeBinding() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToStringStreamListener.class, CustomConverters.class) +// .web(WebApplicationType.NONE) +// .run("--spring.cloud.stream.default.contentType=foo/bar", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage).isNotNull(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("FooBarMessageConverter"); +// assertThat(outputMessage.getHeaders().get(MessageHeaders.CONTENT_TYPE)) +// .isEqualTo(MimeType.valueOf("foo/bar")); +// } +// +// // Failure tests +// +// @Test +// public void _jsonToPojoWrongDefaultContentTypeProperty() { +// ApplicationContext context = new SpringApplicationBuilder( +// PojoToPojoStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.default.contentType=text/plain", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// TestChannelBinder binder = context.getBean(TestChannelBinder.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// assertThat(binder.getLastError().getPayload() instanceof MessagingException) +// .isTrue(); +// } +// +// @Test +// @Ignore +// public void _toStringDefaultContentTypePropertyUnknownContentType() { +// ApplicationContext context = new SpringApplicationBuilder( +// StringToStringStreamListener.class).web(WebApplicationType.NONE).run( +// "--spring.cloud.stream.default.contentType=foo/bar", +// "--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// TestChannelBinder binder = context.getBean(TestChannelBinder.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// assertThat( +// binder.getLastError().getPayload() instanceof MessageConversionException) +// .isTrue(); +// } +// +// @Test +// public void toCollectionWithParameterizedType() { +// ApplicationContext context = new SpringApplicationBuilder( +// CollectionWithParameterizedTypes.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "[{\"person\":{\"name\":\"jon\"},\"id\":123},{\"person\":{\"name\":\"jane\"},\"id\":456}]"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(outputMessage.getPayload()).isEqualTo(jsonPayload.getBytes()); +// } +// +// // ====== +// @Test +// public void testWithMapInputParameter() { +// ApplicationContext context = new SpringApplicationBuilder( +// MapInputConfiguration.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void testWithMapPayloadParameter() { +// ApplicationContext context = new SpringApplicationBuilder( +// MapInputConfiguration.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void testWithListInputParameter() { +// ApplicationContext context = new SpringApplicationBuilder( +// ListInputConfiguration.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "[\"foo\",\"bar\"]"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void testWithMessageHeadersInputParameter() { +// ApplicationContext context = new SpringApplicationBuilder( +// MessageHeadersInputConfiguration.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "{\"name\":\"oleg\"}"; +// source.send(new GenericMessage<>(jsonPayload.getBytes())); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isNotEqualTo(jsonPayload); +// assertThat(outputMessage.getHeaders().containsKey(MessageHeaders.ID)).isTrue(); +// assertThat(outputMessage.getHeaders().containsKey(MessageHeaders.CONTENT_TYPE)) +// .isTrue(); +// } +// +// @Test +// public void testWithTypelessInputParameterAndOctetStream() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessPayloadConfiguration.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "[\"foo\",\"bar\"]"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()) +// .setHeader(MessageHeaders.CONTENT_TYPE, +// MimeTypeUtils.APPLICATION_OCTET_STREAM) +// .build()); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void testWithTypelessInputParameterAndServiceActivator() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessPayloadConfigurationSA.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "[\"foo\",\"bar\"]"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()).build()); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @Test +// public void testWithTypelessMessageInputParameterAndServiceActivator() { +// ApplicationContext context = new SpringApplicationBuilder( +// TypelessMessageConfigurationSA.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// String jsonPayload = "[\"foo\",\"bar\"]"; +// source.send(MessageBuilder.withPayload(jsonPayload.getBytes()).build()); +// Message outputMessage = target.receive(); +// assertThat(new String(outputMessage.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo(jsonPayload); +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class CollectionWithParameterizedTypes { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public List> echo(List> value) { +// assertThat(value.get(0) != null).isTrue(); +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TextInJsonOutListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Message echo(String value) { +// return MessageBuilder.withPayload(value).setHeader( +// MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class PojoToPojoStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Person echo(Person value) { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class PojoToStringStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public String echo(Person value) { +// return value.toString(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class PojoToByteArrayStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public byte[] echo(Person value) { +// return value.toString().getBytes(StandardCharsets.UTF_8); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class ByteArrayToPojoStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Person echo(byte[] value) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// return mapper.readValue(value, Person.class); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class StringToPojoStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Person echo(String value) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// return mapper.readValue(value, Person.class); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessToPojoStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Person echo(Object value) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// // assume it is string because CT is text/plain +// return value instanceof byte[] +// ? mapper.readValue((byte[]) value, Person.class) +// : mapper.readValue((String) value, Person.class); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessMessageToPojoStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Person echo(Message message) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// // assume it is string because CT is text/plain +// return message.getPayload() instanceof byte[] +// ? mapper.readValue((byte[]) message.getPayload(), Person.class) +// : mapper.readValue((String) message.getPayload(), Person.class); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessToMessageStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Message echo(Object value) throws Exception { +// return MessageBuilder.withPayload(value.toString()) +// .setHeader("contentType", new MimeType("text", "plain")).build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessToMessageTextOnlyContentTypeStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Message echo(Object value) throws Exception { +// return MessageBuilder.withPayload(value.toString()) +// .setHeader("contentType", new MimeType("text")).build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class ByteArrayToByteArrayStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public byte[] echo(byte[] value) { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class StringToStringStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public String echo(String value) { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// /* +// * Uncomment to test MBean name quoting for ":" in bean name component of ObjectName. +// * Commented to avoid "InstanceAlreadyExistsException" in other tests. +// */ +// // @EnableIntegrationMBeanExport +// public static class StringToMapStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public String echo(@Payload Map value) { +// return (String) value.get("name"); +// } +// +// @ServiceActivator(inputChannel = "input:foo.myGroup.errors") +// public void error(Message message) { +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class StringToMapMessageStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public String echo(Message> value) { +// assertThat(value.getPayload() instanceof Map).isTrue(); +// return (String) value.getPayload().get("name"); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class PojoMessageToStringMessageStreamListener { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Message echo(Message value) { +// return MessageBuilder.withPayload(value.getPayload().toString()) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) +// .build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class PojoMessageToStringMessageServiceActivator { +// +// @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) +// public Message echo(Message value) { +// return MessageBuilder.withPayload(value.getPayload().toString()) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) +// .build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class StringMessageToStringMessageStreamListener { +// +// @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) +// public Message echo(Message value) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// Person person = mapper.readValue(value.getPayload(), Person.class); +// return MessageBuilder.withPayload(person.toString()) +// .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.TEXT_PLAIN) +// .build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class ByteArrayMessageToStringJsonMessageStreamListener { +// +// @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) +// public Message echo(Message value) throws Exception { +// ObjectMapper mapper = new ObjectMapper(); +// Person person = mapper.readValue(value.getPayload(), Person.class); +// person.setName("bob"); +// String json = mapper.writeValueAsString(person); +// return MessageBuilder.withPayload(json).build(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class InternalPipeLine { +// +// @StreamListener(Processor.INPUT) +// @SendTo("internalChannel") +// public String handleA(Person value) { +// return "{\"name\":\"" + value.getName().toUpperCase() + "\"}"; +// } +// +// @Bean +// public MessageChannel internalChannel() { +// return new DirectChannel(); +// } +// +// @StreamListener("internalChannel") +// @SendTo(Processor.OUTPUT) +// public String handleB(Person value) { +// return value.toString(); +// } +// +// } +// +// public static class Employee

{ +// +// private P person; +// +// private int id; +// +// public int getId() { +// return this.id; +// } +// +// public void setId(int id) { +// this.id = id; +// } +// +// public P getPerson() { +// return this.person; +// } +// +// public void setPerson(P person) { +// this.person = person; +// } +// +// } +// +// public static class Person { +// +// private String name; +// +// public Person() { +// this(null); +// } +// +// public Person(String name) { +// this.name = name; +// } +// +// public String getName() { +// return this.name; +// } +// +// public void setName(String name) { +// this.name = name; +// } +// +// @Override +// public String toString() { +// return this.name; +// } +// +// } +// +// @Configuration +// public static class CustomConverters { +// +// @Bean +// public FooBarMessageConverter fooBarMessageConverter() { +// return new FooBarMessageConverter(MimeType.valueOf("foo/bar")); +// } +// +// @Bean +// public AlwaysStringKryoMessageConverter kryoOverrideMessageConverter() { +// return new AlwaysStringKryoMessageConverter( +// MimeType.valueOf("application/x-java-object")); +// } +// +// /** +// * Even though this MessageConverter has nothing to do with Kryo it still shows +// * how Kryo conversion can be customized/overriden since it simply overriding a +// * converter for contentType 'application/x-java-object'. +// * +// */ +// public static class AlwaysStringKryoMessageConverter +// extends AbstractMessageConverter { +// +// public AlwaysStringKryoMessageConverter(MimeType supportedMimeType) { +// super(supportedMimeType); +// } +// +// @Override +// protected boolean supports(Class clazz) { +// return clazz == null || String.class.isAssignableFrom(clazz); +// } +// +// @Override +// protected Object convertFromInternal(Message message, Class targetClass, +// @Nullable Object conversionHint) { +// return this.getClass().getSimpleName(); +// } +// +// @Override +// protected Object convertToInternal(Object payload, +// @Nullable MessageHeaders headers, @Nullable Object conversionHint) { +// return ((String) payload).getBytes(StandardCharsets.UTF_8); +// } +// +// } +// +// public static class FooBarMessageConverter extends AbstractMessageConverter { +// +// protected FooBarMessageConverter(MimeType supportedMimeType) { +// super(supportedMimeType); +// } +// +// @Override +// protected boolean supports(Class clazz) { +// return clazz != null && String.class.isAssignableFrom(clazz); +// } +// +// @Override +// protected Object convertFromInternal(Message message, Class targetClass, +// @Nullable Object conversionHint) { +// return this.getClass().getSimpleName(); +// } +// +// @Override +// protected Object convertToInternal(Object payload, +// @Nullable MessageHeaders headers, @Nullable Object conversionHint) { +// return ((String) payload).getBytes(StandardCharsets.UTF_8); +// } +// +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class MapInputConfiguration { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Map echo(Map value) throws Exception { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class MapPayloadConfiguration { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Map echo(Message> value) throws Exception { +// return value.getPayload(); +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class ListInputConfiguration { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public List echo(List value) throws Exception { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class MessageHeadersInputConfiguration { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Map echo(MessageHeaders value) throws Exception { +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessPayloadConfiguration { +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public Object echo(Object value) throws Exception { +// System.out.println(value); +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessPayloadConfigurationSA { +// +// @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) +// public Object echo(Object value) throws Exception { +// System.out.println(value); +// return value; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class TypelessMessageConfigurationSA { +// +// @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) +// public Object echo(Message value) throws Exception { +// System.out.println(value.getPayload()); +// return value.getPayload(); +// } +// +// } +// +//} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java deleted file mode 100644 index f7134c610..000000000 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2019-2019 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder.tck; - -import org.junit.Test; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binder.test.InputDestination; -import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Import; -import org.springframework.messaging.Message; -import org.springframework.messaging.support.GenericMessage; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Oleg Zhurakousky - * - */ -public class ErrorHandlingTests { - - @Test - public void testGlobalErrorWithMessage() { - ApplicationContext context = new SpringApplicationBuilder( - GlobalErrorHandlerWithErrorMessageConfig.class) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - source.send(new GenericMessage<>("foo".getBytes())); - GlobalErrorHandlerWithErrorMessageConfig config = context - .getBean(GlobalErrorHandlerWithErrorMessageConfig.class); - assertThat(config.globalErroInvoked).isTrue(); - } - - @Test - public void testGlobalErrorWithThrowable() { - ApplicationContext context = new SpringApplicationBuilder( - GlobalErrorHandlerWithThrowableConfig.class).web(WebApplicationType.NONE) - .run("--spring.jmx.enabled=false"); - InputDestination source = context.getBean(InputDestination.class); - source.send(new GenericMessage<>("foo".getBytes())); - GlobalErrorHandlerWithThrowableConfig config = context - .getBean(GlobalErrorHandlerWithThrowableConfig.class); - assertThat(config.globalErroInvoked).isTrue(); - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class GlobalErrorHandlerWithErrorMessageConfig { - - private boolean globalErroInvoked; - - @StreamListener(target = Processor.INPUT) - public void input(final String value) { - throw new RuntimeException("test exception"); - } - - @StreamListener("errorChannel") - public void generalError(Message message) { - this.globalErroInvoked = true; - } - - } - - @EnableBinding(Processor.class) - @Import(TestChannelBinderConfiguration.class) - @EnableAutoConfiguration - public static class GlobalErrorHandlerWithThrowableConfig { - - private boolean globalErroInvoked; - - @StreamListener(target = Processor.INPUT) - public void input(final String value) { - throw new RuntimeException("test exception"); - } - - @StreamListener("errorChannel") - public void generalError(Throwable exception) { - this.globalErroInvoked = true; - } - - } - -} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java.todo b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java.todo new file mode 100644 index 000000000..848ec84ce --- /dev/null +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ErrorHandlingTests.java.todo @@ -0,0 +1,104 @@ +///* +// * Copyright 2019-2019 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. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.springframework.cloud.stream.binder.tck; +// +//import org.junit.Test; +// +//import org.springframework.boot.WebApplicationType; +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +//import org.springframework.boot.builder.SpringApplicationBuilder; +//import org.springframework.cloud.stream.annotation.EnableBinding; +//import org.springframework.cloud.stream.annotation.StreamListener; +//import org.springframework.cloud.stream.binder.test.InputDestination; +//import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; +//import org.springframework.cloud.stream.messaging.Processor; +//import org.springframework.context.ApplicationContext; +//import org.springframework.context.annotation.Import; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.support.GenericMessage; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +///** +// * @author Oleg Zhurakousky +// * +// */ +//public class ErrorHandlingTests { +// +// @Test +// public void testGlobalErrorWithMessage() { +// ApplicationContext context = new SpringApplicationBuilder( +// GlobalErrorHandlerWithErrorMessageConfig.class) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// source.send(new GenericMessage<>("foo".getBytes())); +// GlobalErrorHandlerWithErrorMessageConfig config = context +// .getBean(GlobalErrorHandlerWithErrorMessageConfig.class); +// assertThat(config.globalErroInvoked).isTrue(); +// } +// +// @Test +// public void testGlobalErrorWithThrowable() { +// ApplicationContext context = new SpringApplicationBuilder( +// GlobalErrorHandlerWithThrowableConfig.class).web(WebApplicationType.NONE) +// .run("--spring.jmx.enabled=false"); +// InputDestination source = context.getBean(InputDestination.class); +// source.send(new GenericMessage<>("foo".getBytes())); +// GlobalErrorHandlerWithThrowableConfig config = context +// .getBean(GlobalErrorHandlerWithThrowableConfig.class); +// assertThat(config.globalErroInvoked).isTrue(); +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class GlobalErrorHandlerWithErrorMessageConfig { +// +// private boolean globalErroInvoked; +// +// @StreamListener(target = Processor.INPUT) +// public void input(final String value) { +// throw new RuntimeException("test exception"); +// } +// +// @StreamListener("errorChannel") +// public void generalError(Message message) { +// this.globalErroInvoked = true; +// } +// +// } +// +// @EnableBinding(Processor.class) +// @Import(TestChannelBinderConfiguration.class) +// @EnableAutoConfiguration +// public static class GlobalErrorHandlerWithThrowableConfig { +// +// private boolean globalErroInvoked; +// +// @StreamListener(target = Processor.INPUT) +// public void input(final String value) { +// throw new RuntimeException("test exception"); +// } +// +// @StreamListener("errorChannel") +// public void generalError(Throwable exception) { +// this.globalErroInvoked = true; +// } +// +// } +// +//} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java deleted file mode 100644 index f6b0dfae3..000000000 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2017-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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder.test; - -import java.nio.charset.StandardCharsets; - -import org.springframework.boot.ApplicationRunner; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.Input; -import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.binder.PollableMessageSource; -import org.springframework.cloud.stream.messaging.Processor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.SendTo; -import org.springframework.messaging.support.GenericMessage; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Sample spring cloud stream application that demonstrates the usage of - * {@link TestChannelBinder}. - * - * @author Oleg Zhurakousky - * @author Gary Russell - * - */ -@SpringBootApplication -@EnableBinding(SampleStreamApp.PolledConsumer.class) -@Import(TestChannelBinderConfiguration.class) -public class SampleStreamApp { - - public static void main(String[] args) { - ApplicationContext context = new SpringApplicationBuilder(SampleStreamApp.class) - .web(WebApplicationType.NONE).run("--server.port=0"); - InputDestination source = context.getBean(InputDestination.class); - OutputDestination target = context.getBean(OutputDestination.class); - source.send(new GenericMessage("Hello".getBytes())); - - Message message = target.receive(); - assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_8)) - .isEqualTo("Hello"); - } - - @Bean - public ApplicationRunner runner(PollableMessageSource pollableSource) { - return args -> pollableSource.poll(message -> { - System.out.println("Polled payload: " + message.getPayload()); - }); - } - - @StreamListener(Processor.INPUT) - @SendTo(Processor.OUTPUT) - public String receive(String value) { - System.out.println("Handling payload: " + value); - return value; - } - - @ServiceActivator(inputChannel = "input.anonymous.errors") - public void error(String value) { - System.out.println("Handling ERROR payload: " + value); - } - - public interface PolledConsumer extends Processor { - - @Input - PollableMessageSource pollableSource(); - - } - -} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java.todo b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java.todo new file mode 100644 index 000000000..0975cad92 --- /dev/null +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/SampleStreamApp.java.todo @@ -0,0 +1,91 @@ +///* +// * Copyright 2017-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. +// * You may obtain a copy of the License at +// * +// * https://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.springframework.cloud.stream.binder.test; +// +//import java.nio.charset.StandardCharsets; +// +//import org.springframework.boot.ApplicationRunner; +//import org.springframework.boot.WebApplicationType; +//import org.springframework.boot.autoconfigure.SpringBootApplication; +//import org.springframework.boot.builder.SpringApplicationBuilder; +//import org.springframework.cloud.stream.annotation.EnableBinding; +//import org.springframework.cloud.stream.annotation.Input; +//import org.springframework.cloud.stream.annotation.StreamListener; +//import org.springframework.cloud.stream.binder.PollableMessageSource; +//import org.springframework.cloud.stream.messaging.Processor; +//import org.springframework.context.ApplicationContext; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Import; +//import org.springframework.integration.annotation.ServiceActivator; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.handler.annotation.SendTo; +//import org.springframework.messaging.support.GenericMessage; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +///** +// * Sample spring cloud stream application that demonstrates the usage of +// * {@link TestChannelBinder}. +// * +// * @author Oleg Zhurakousky +// * @author Gary Russell +// * +// */ +//@SpringBootApplication +//@EnableBinding(SampleStreamApp.PolledConsumer.class) +//@Import(TestChannelBinderConfiguration.class) +//public class SampleStreamApp { +// +// public static void main(String[] args) { +// ApplicationContext context = new SpringApplicationBuilder(SampleStreamApp.class) +// .web(WebApplicationType.NONE).run("--server.port=0"); +// InputDestination source = context.getBean(InputDestination.class); +// OutputDestination target = context.getBean(OutputDestination.class); +// source.send(new GenericMessage("Hello".getBytes())); +// +// Message message = target.receive(); +// assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_8)) +// .isEqualTo("Hello"); +// } +// +// @Bean +// public ApplicationRunner runner(PollableMessageSource pollableSource) { +// return args -> pollableSource.poll(message -> { +// System.out.println("Polled payload: " + message.getPayload()); +// }); +// } +// +// @StreamListener(Processor.INPUT) +// @SendTo(Processor.OUTPUT) +// public String receive(String value) { +// System.out.println("Handling payload: " + value); +// return value; +// } +// +// @ServiceActivator(inputChannel = "input.anonymous.errors") +// public void error(String value) { +// System.out.println("Handling ERROR payload: " + value); +// } +// +// public interface PolledConsumer extends Processor { +// +// @Input +// PollableMessageSource pollableSource(); +// +// } +// +//} diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/function/ImplicitFunctionBindingTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/function/ImplicitFunctionBindingTests.java index 523634436..7f225cc57 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/function/ImplicitFunctionBindingTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/function/ImplicitFunctionBindingTests.java @@ -45,8 +45,6 @@ import org.springframework.cloud.function.context.FunctionType; import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.cloud.stream.binder.Binding; import org.springframework.cloud.stream.binder.BindingCreatedEvent; import org.springframework.cloud.stream.binder.test.FunctionBindingTestUtils; @@ -56,7 +54,6 @@ import org.springframework.cloud.stream.binder.test.TestChannelBinderConfigurati import org.springframework.cloud.stream.binding.BindingsLifecycleController; import org.springframework.cloud.stream.binding.BindingsLifecycleController.State; import org.springframework.cloud.stream.messaging.DirectWithAttributesChannel; -import org.springframework.cloud.stream.messaging.Sink; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -466,16 +463,16 @@ public class ImplicitFunctionBindingTests { } } - @Test - public void testFunctionConfigDisabledIfStreamListenerIsUsed() { - System.clearProperty("spring.cloud.function.definition"); - try (ConfigurableApplicationContext context = new SpringApplicationBuilder( - TestChannelBinderConfiguration.getCompleteConfiguration(LegacyConfiguration.class)) - .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false")) { - - assertThat(context.getBean("supplierInitializer").getClass().getSimpleName()).isEqualTo("NullBean"); - } - } +// @Test +// public void testFunctionConfigDisabledIfStreamListenerIsUsed() { +// System.clearProperty("spring.cloud.function.definition"); +// try (ConfigurableApplicationContext context = new SpringApplicationBuilder( +// TestChannelBinderConfiguration.getCompleteConfiguration(LegacyConfiguration.class)) +// .web(WebApplicationType.NONE).run("--spring.jmx.enabled=false")) { +// +// assertThat(context.getBean("supplierInitializer").getClass().getSimpleName()).isEqualTo("NullBean"); +// } +// } @Test public void testDeclaredTypeVsActualInstance() { @@ -1340,16 +1337,6 @@ public class ImplicitFunctionBindingTests { } } - @EnableAutoConfiguration - @EnableBinding(Sink.class) - public static class LegacyConfiguration { - - @StreamListener(Sink.INPUT) - public void handle(String value) { - - } - } - @EnableAutoConfiguration public static class EmptyConfiguration {