Initial take on removing StreamListener

StreamListener was deprecated in 3.0.x.

This commit is the initial one in removing StreamListener and
it's related components completely in 4.0.x.

More tests need to be adjusted and migrated which will be addressed
in later commits.
This commit is contained in:
Soby Chacko
2022-01-07 17:53:41 -05:00
parent 0ee4b41b2f
commit 2fe7cf58c1
40 changed files with 1787 additions and 6288 deletions

View File

@@ -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<String, Object>) testPojoWithAnnotatedArguments.receivedArguments
.get(1)).containsEntry(MessageHeaders.CONTENT_TYPE,
MimeType.valueOf("application/json"));
assertThat((Map<String, String>) 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<Object> receivedArguments = new ArrayList<>();
@StreamListener(Processor.INPUT)
public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo,
@Headers Map<String, Object> 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<Object> receivedArguments = new ArrayList<>();
@StreamListener
public void receive(
@Input(Processor.INPUT) @Payload StreamListenerTestUtils.FooPojo fooPojo,
@Headers Map<String, Object> 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<Object> receivedArguments = new ArrayList<>();
@StreamListener(Processor.INPUT)
public void receive(
@Valid StreamListenerTestUtils.PojoWithValidation pojoWithValidation) {
this.receivedArguments.add(pojoWithValidation);
}
}
}

View File

@@ -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<StreamListenerTestUtils.FooPojo> 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<String, Object> 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);
}
}
}

View File

@@ -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<StreamListenerTestUtils.FooPojo> receivedFoo = new ArrayList<>();
List<StreamListenerTestUtils.BarPojo> 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<StreamListenerTestUtils.FooPojo> receivedFoo = new ArrayList<>();
List<StreamListenerTestUtils.BarPojo> receivedBar = new ArrayList<>();
@StreamListener(value = Sink.INPUT, condition = "headers['type']=='foo'")
public void receive(@Payload StreamListenerTestUtils.FooPojo fooPojo) {
this.receivedFoo.add(fooPojo);
}
}
}

View File

@@ -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<StreamListenerTestUtils.FooPojo> receivedArguments = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(1);
@StreamListener(Sink.INPUT)
public void receive(StreamListenerTestUtils.FooPojo fooPojo) {
this.receivedArguments.add(fooPojo);
this.latch.countDown();
}
}
}

View File

@@ -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<T extends Base> {
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<String> fooMessage) {
return null;
}
@StreamListener(Processor.INPUT)
@SendTo(Processor.OUTPUT)
public String receiveDuplicateMapping(Message<String> fooMessage) {
return null;
}
}
@EnableBinding(Sink.class)
@EnableAutoConfiguration
public static class TestDuplicateMappingFromAbstractMethod
implements GenericSink<TestBase> {
@Override
@StreamListener(Sink.INPUT)
public void testMethod(TestBase msg) {
}
}
public class TestBase implements Base {
}
}

View File

@@ -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<String> message = (Message<String>) 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<StreamListenerTestUtils.FooPojo> receivedPojos = new ArrayList<>();
}
}

View File

@@ -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<String> result = (Message<String>) 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<byte[]> 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<String> result = (Message<String>) 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<String> result = (Message<String>) 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<String> result = (Message<String>) 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<String> convertMessageBody(Message<String> 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());
}
});
}
}
}

View File

@@ -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<String> message = (Message<String>) 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<String> 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<String> fooMessage) {
this.receivedMessages.add(fooMessage);
StreamListenerTestUtils.BarPojo barPojo = new StreamListenerTestUtils.BarPojo();
barPojo.setBar(fooMessage.getPayload());
return barPojo;
}
}
public static class TestPojoWithMessageArgument {
List<Message<String>> receivedMessages = new ArrayList<>();
}
}

View File

@@ -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() {
}
}
}

View File

@@ -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<String> message = (Message<String>) 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<String> message = (Message<String>) 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<StreamListenerTestUtils.FooPojo> receivedPojos = new ArrayList<>();
}
}

View File

@@ -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<StreamListenerSetupMethodOrchestrator> field1;
field1 = (LinkedHashSet<StreamListenerSetupMethodOrchestrator>) ReflectionUtils
.getField(field, this.streamListenerAnnotationBeanPostProcessor);
List<StreamListenerSetupMethodOrchestrator> 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
}
}
}

View File

@@ -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<String> message = (Message<String>) 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<StreamListenerTestUtils.FooPojo> receivedPojos = new ArrayList<>();
}
}

View File

@@ -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<String> message = (Message<String>) 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<StreamListenerTestUtils.FooPojo> receivedPojos = new ArrayList<>();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<String> result = (Message<String>) 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());
}
});
}
}
}

View File

@@ -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<StreamListenerTestUtils.FooPojo> receivedFoo = new ArrayList<>();
List<StreamListenerTestUtils.BarPojo> 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;
}
}
}

View File

@@ -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<String> received = (Message<String>) ((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 + "'}";
}
}
}

View File

@@ -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<String> received = (Message<String>) ((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 + "'}";
// }
//
// }
//
//}

View File

@@ -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<String> message = (Message<String>) 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<String> message = (Message<String>) 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<String> message = (Message<String>) 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<byte[]> message = (Message<byte[]>) 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<byte[]> message = (Message<byte[]>) 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<byte[]> message = (Message<byte[]>) 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<String> message = (Message<String>) 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<String, Object> headers = (Map<String, Object>) 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<String, Object> headers = (Map<String, Object>) sourceApp.arguments.pop();
sourceApp.arguments.pop();
assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE))
.includes(MimeTypeUtils.IMAGE_GIF));
headers = (Map<String, Object>) 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<? super Object> arguments = new LinkedList<>();
@StreamListener("POJO_INPUT")
public void receive(User user, @Headers Map<String, Object> 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<String, Object> headers) {
this.arguments.push(data);
this.arguments.push(headers);
}
}
}

View File

@@ -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<String> message = (Message<String>) 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<String> message = (Message<String>) 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<String> message = (Message<String>) 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<byte[]> message = (Message<byte[]>) 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<byte[]> message = (Message<byte[]>) 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<byte[]> message = (Message<byte[]>) 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<String> message = (Message<String>) 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<String, Object> headers = (Map<String, Object>) 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<String, Object> headers = (Map<String, Object>) sourceApp.arguments.pop();
// sourceApp.arguments.pop();
// assertThat(((MimeType) headers.get(MessageHeaders.CONTENT_TYPE))
// .includes(MimeTypeUtils.IMAGE_GIF));
// headers = (Map<String, Object>) 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<? super Object> arguments = new LinkedList<>();
//
// @StreamListener("POJO_INPUT")
// public void receive(User user, @Headers Map<String, Object> 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<String, Object> headers) {
// this.arguments.push(data);
// this.arguments.push(headers);
// }
//
// }
//
//}