diff --git a/specs/spring-cloud-contract-spec-kotlin/pom.xml b/specs/spring-cloud-contract-spec-kotlin/pom.xml
index 61ae965805..b14b22f6b8 100644
--- a/specs/spring-cloud-contract-spec-kotlin/pom.xml
+++ b/specs/spring-cloud-contract-spec-kotlin/pom.xml
@@ -31,6 +31,26 @@
kotlin-stdlib-jdk8
${kotlin.version}
+
+ org.jetbrains.kotlin
+ kotlin-compiler
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-scripting-compiler
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-script-runtime
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-script-util
+ ${kotlin.version}
+
org.jetbrains.kotlin
kotlin-test
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt
new file mode 100644
index 0000000000..98285809fc
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013-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.contract.spec.internal
+
+import org.springframework.cloud.contract.spec.Contract
+import org.springframework.cloud.contract.spec.ContractConverter
+import java.io.File
+import javax.script.ScriptEngineManager
+
+/**
+ * @author Tim Ysewyn
+ */
+class KotlinContractConverter: ContractConverter> {
+
+ private val ext = "kts"
+
+ constructor() {
+ // Sets an {@code idea.use.native.fs.for.win} system property to {@code false}
+ // to disable a native engine discovery for Windows: may be resolved in the future Kotlin versions.
+ System.setProperty("idea.use.native.fs.for.win", "false")
+ }
+
+ override fun isAccepted(file: File): Boolean {
+ return ext == file.extension
+ }
+
+ override fun convertFrom(file: File): Collection {
+ val eval = file.reader().use {
+ // Get a new engine every time we need to process a file.
+ // Reusing the script engine could leak context and will fail subsequent evals
+ ScriptEngineManager().getEngineByExtension(ext).eval(it)
+ }
+ return when (eval) {
+ is Contract -> listOf(eval)
+ is Iterable<*> -> eval.filterIsInstance(Contract::class.java)
+ is Array<*> -> eval.filterIsInstance(Contract::class.java)
+ else -> emptyList()
+ }
+ }
+
+ override fun convertTo(contract: Collection) = contract.toList()
+}
\ No newline at end of file
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt
index 267d9993b2..bf7de2fea8 100644
--- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt
+++ b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt
@@ -44,20 +44,20 @@ open class RequestDsl : CommonDsl(), RegexCreatingProperty {
this.method(method.toString())
}
- fun url(url: String): Url {
- return Url(url)
+ fun url(url: String) {
+ this.url = Url(url)
}
- fun url(url: DslProperty): Url {
- return Url(url)
+ fun url(url: DslProperty) {
+ this.url = Url(url)
}
- fun urlPath(url: String): UrlPath {
- return UrlPath(url)
+ fun urlPath(url: String) {
+ this.urlPath = UrlPath(url)
}
- fun urlPath(url: DslProperty): UrlPath {
- return UrlPath(url)
+ fun urlPath(url: DslProperty) {
+ this.urlPath = UrlPath(url)
}
fun headers(headers: Headers.() -> Unit) {
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
new file mode 100644
index 0000000000..f8f5900378
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
@@ -0,0 +1 @@
+org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
\ No newline at end of file
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000000..331f97675a
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.cloud.contract.spec.ContractConverter=\
+org.springframework.cloud.contract.spec.internal.KotlinContractConverter
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt
new file mode 100644
index 0000000000..4d2cd56536
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013-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.contract.spec.internal
+
+import org.junit.Test
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class KotlinContractConverterTest {
+
+ @Test
+ fun `accept kts files`() {
+ assertTrue(KotlinContractConverter().isAccepted(file("contracts/singleDefinition.kts")))
+ }
+
+ @Test
+ fun `should convert single contract definition`() {
+ val converter = KotlinContractConverter()
+ val contracts = converter.convertFrom(file("contracts/singleDefinition.kts"))
+ assertEquals(1, contracts.size)
+ }
+
+ @Test
+ fun `should convert multiple contract definitions`() {
+ val converter = KotlinContractConverter()
+ val contracts = converter.convertFrom(file("contracts/multipleDefinitions.kts"))
+ assertEquals(2, contracts.size)
+ }
+
+ private fun file(filename: String) = File(javaClass.classLoader.getResource(filename)!!.toURI())
+}
\ No newline at end of file
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts
new file mode 100644
index 0000000000..8838386cd8
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2013-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 contracts
+
+import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
+
+arrayOf(
+ contract {
+ request {
+ method("GET")
+ url("/frauds")
+ }
+ response {
+ status(200)
+ body("count" to 200)
+ headers {
+ contentType("application/vnd.fraud.v1+json")
+ }
+ }
+ },
+ contract {
+ request {
+ method("GET")
+ url("/drunks")
+ }
+ response {
+ status(200)
+ body("count" to 100)
+ headers {
+ contentType("application/vnd.fraud.v1+json")
+ }
+ }
+ }
+)
\ No newline at end of file
diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts
new file mode 100644
index 0000000000..f3047ff2c7
--- /dev/null
+++ b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013-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 contracts
+
+import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract
+
+contract {
+ request {
+ method("PUT")
+ url("/fraudcheck")
+ body("clientId" to value(consumer(regex("[0-9]{10}")), producer("1234567890")),
+ "loanAmount" to 123.123
+ )
+ headers {
+ contentType("application/vnd.fraud.v1+json")
+ }
+
+ }
+ response {
+ status(200)
+ body(
+ "fraudCheckStatus" to "OK",
+ "rejectionReason" to listOf(value(consumer(null), producer("assertThatRejectionReasonIsNull(\$it)")))
+ )
+ headers {
+ contentType("application/vnd.fraud.v1+json")
+ }
+ }
+}
\ No newline at end of file