diff --git a/build.gradle b/build.gradle index b87537373f..d854b075c9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,12 @@ buildscript { + ext.kotlinVersion = '1.2.40' repositories { maven { url 'https://repo.spring.io/plugins-release' } } dependencies { classpath 'io.spring.gradle:docbook-reference-plugin:0.3.1' classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } @@ -58,6 +60,7 @@ subprojects { subproject -> apply plugin: 'idea' apply plugin: 'jacoco' apply plugin: 'checkstyle' + apply plugin: 'kotlin' sourceSets { test { @@ -72,11 +75,18 @@ subprojects { subproject -> targetCompatibility = 1.8 } + compileTestKotlin { + kotlinOptions { + jvmTarget = '1.8' + } + } + ext { activeMqVersion = '5.15.3' apacheSshdVersion = '1.7.0' aspectjVersion = '1.9.0' assertjVersion = '3.9.1' + assertkVersion = '0.10' boonVersion = '0.34' commonsDbcp2Version = '2.2.0' commonsIoVersion = '2.6' @@ -161,6 +171,14 @@ subprojects { subproject -> testRuntime "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion" testRuntime "org.apache.logging.log4j:log4j-jcl:$log4jVersion" + + testCompile("com.willowtreeapps.assertk:assertk:$assertkVersion") { + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-reflect' + } + + testCompile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + testRuntime "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" + } // enable all compiler warnings; individual projects may customize further diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java index ee2187293d..dc23403135 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationFlowDefinition.java @@ -86,6 +86,7 @@ import org.springframework.integration.transformer.HeaderFilter; import org.springframework.integration.transformer.MessageTransformingHandler; import org.springframework.integration.transformer.MethodInvokingTransformer; import org.springframework.integration.transformer.Transformer; +import org.springframework.integration.util.ClassUtils; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; @@ -633,7 +634,7 @@ public abstract class IntegrationFlowDefinition B handle(Class
payloadType, GenericHandler
handler,
Consumer selector) {
+ MessageSelector messageSelector = wrapToMessageSelectorIfNecessary(selector);
+ this.handler.addRecipient(channelName, messageSelector);
+ return _this();
+ }
+
+ private MessageSelector wrapToMessageSelectorIfNecessary(GenericSelector selector) {
MessageSelector messageSelector;
if (selector instanceof MessageSelector) {
messageSelector = (MessageSelector) selector;
}
else {
- messageSelector =
- isLambda(selector)
- ? new MethodInvokingSelector(new LambdaMessageProcessor(selector, null))
- : new MethodInvokingSelector(selector);
+ messageSelector = new MethodInvokingSelector(selector, ClassUtils.SELECTOR_ACCEPT_METHOD);
}
- this.handler.addRecipient(channelName, messageSelector);
- return _this();
- }
-
- private static boolean isLambda(Object o) {
- Class> aClass = o.getClass();
- return aClass.isSynthetic() && !aClass.isAnonymousClass() && !aClass.isLocalClass();
+ return messageSelector;
}
/**
@@ -170,16 +167,7 @@ public class RecipientListRouterSpec extends AbstractRouterSpec selector) {
- MessageSelector messageSelector;
- if (selector instanceof MessageSelector) {
- messageSelector = (MessageSelector) selector;
- }
- else {
- messageSelector =
- isLambda(selector)
- ? new MethodInvokingSelector(new LambdaMessageProcessor(selector, null))
- : new MethodInvokingSelector(selector);
- }
+ MessageSelector messageSelector = wrapToMessageSelectorIfNecessary(selector);
this.handler.addRecipient(channel, messageSelector);
return _this();
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/ClassUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/util/ClassUtils.java
index 9558a76eb7..1912caea63 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/util/ClassUtils.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/util/ClassUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +16,63 @@
package org.springframework.integration.util;
+import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
+
+import org.springframework.integration.core.GenericSelector;
+import org.springframework.integration.transformer.GenericTransformer;
+import org.springframework.util.ReflectionUtils;
/**
* @author Mark Fisher
+ * @author Artem Bilan
+ *
* @since 2.0
*/
public abstract class ClassUtils {
+ /**
+ * The {@link Function#apply(Object)} method object.
+ */
+ public static final Method FUNCTION_APPLY_METHOD =
+ ReflectionUtils.findMethod(Function.class, "apply", (Class>[]) null);
+
+ /**
+ * The {@link GenericSelector#accept(Object)} method object.
+ */
+ public static final Method SELECTOR_ACCEPT_METHOD =
+ ReflectionUtils.findMethod(GenericSelector.class, "accept", (Class>[]) null);
+
+ /**
+ * The {@link GenericSelector#accept(Object)} method object.
+ */
+ public static final Method TRANSFORMER_TRANSFORM_METHOD =
+ ReflectionUtils.findMethod(GenericTransformer.class, "transform", (Class>[]) null);
+
+ /**
+ * The {@code org.springframework.integration.handler.GenericHandler#handle(Object, Map)} method object.
+ */
+ public static final Method HANDLER_HANDLE_METHOD;
+
+ static {
+ Class> genericHandlerClass = null;
+ try {
+ genericHandlerClass =
+ org.springframework.util.ClassUtils.forName(
+ "org.springframework.integration.handler.GenericHandler",
+ org.springframework.util.ClassUtils.getDefaultClassLoader());
+ }
+ catch (ClassNotFoundException e) {
+ ReflectionUtils.rethrowRuntimeException(e);
+ }
+
+ HANDLER_HANDLE_METHOD = ReflectionUtils.findMethod(genericHandlerClass, "handle", (Class>[]) null);
+ }
+
+
/**
* Map with primitive wrapper type as key and corresponding primitive
* type as value, for example: Integer.class -> int.class.
diff --git a/spring-integration-core/src/test/kotlin/org/springframework/integration/dsl/routers/RouterDslTests.kt b/spring-integration-core/src/test/kotlin/org/springframework/integration/dsl/routers/RouterDslTests.kt
new file mode 100644
index 0000000000..5bb7db4a76
--- /dev/null
+++ b/spring-integration-core/src/test/kotlin/org/springframework/integration/dsl/routers/RouterDslTests.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 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
+ *
+ * http://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.integration.dsl.routers
+
+import assertk.assert
+import assertk.assertions.isEqualTo
+import assertk.assertions.isInstanceOf
+import assertk.assertions.isNotNull
+import org.junit.jupiter.api.Test
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Qualifier
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.integration.config.EnableIntegration
+import org.springframework.integration.dsl.IntegrationFlow
+import org.springframework.messaging.MessageChannel
+import org.springframework.messaging.PollableChannel
+import org.springframework.messaging.support.GenericMessage
+import org.springframework.test.annotation.DirtiesContext
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig
+
+/**
+ * @author Artem Bilan
+ *
+ * @since 5.0.5
+ */
+@SpringJUnitConfig
+@DirtiesContext
+class RouterDslTests {
+
+ @Autowired
+ @Qualifier("routerTwoSubFlows.input")
+ private lateinit var routerTwoSubFlowsInput: MessageChannel
+
+ @Autowired
+ @Qualifier("routerTwoSubFlowsOutput")
+ private lateinit var routerTwoSubFlowsOutput: PollableChannel
+
+ @Test
+ fun `route to two subflows using lambda`() {
+
+ this.routerTwoSubFlowsInput.send(GenericMessage