diff --git a/pom.xml b/pom.xml
index ba054091e7..c06305b8a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
1.3.0
1.0.30.RELEASE
- 1.6.21
+ 1.8.22
1.9.4
2.6.0
diff --git a/specs/spring-cloud-contract-spec-kotlin/pom.xml b/specs/spring-cloud-contract-spec-kotlin/pom.xml
index f986b16419..ce955604dd 100644
--- a/specs/spring-cloud-contract-spec-kotlin/pom.xml
+++ b/specs/spring-cloud-contract-spec-kotlin/pom.xml
@@ -26,6 +26,18 @@
org.jetbrains.kotlin
kotlin-compiler-embeddable
+
+ org.jetbrains.kotlin
+ kotlin-scripting-common
+
+
+ org.jetbrains.kotlin
+ kotlin-scripting-jvm
+
+
+ org.jetbrains.kotlin
+ kotlin-scripting-jvm-host
+
org.jetbrains.kotlin
kotlin-scripting-compiler-embeddable
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
index 6be6784243..d332462f6d 100644
--- 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
@@ -22,7 +22,14 @@ import org.springframework.cloud.contract.spec.ContractConverter
import java.io.File
import java.net.URLClassLoader.newInstance
import java.util.concurrent.atomic.AtomicInteger
-import javax.script.ScriptEngineManager
+import kotlin.script.experimental.api.EvaluationResult
+import kotlin.script.experimental.api.ResultValue
+import kotlin.script.experimental.api.ResultWithDiagnostics
+import kotlin.script.experimental.api.ScriptCompilationConfiguration
+import kotlin.script.experimental.host.toScriptSource
+import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
+import kotlin.script.experimental.jvm.jvm
+import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
/**
* Converter that will convert the Kotlin DSL to Java DSL.
@@ -32,62 +39,73 @@ import javax.script.ScriptEngineManager
*/
class KotlinContractConverter : ContractConverter> {
- private val ext = "kts"
+ 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")
- }
+ 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 isAccepted(file: File): Boolean {
+ return ext == file.extension
+ }
- override fun convertFrom(file: File): Collection {
- val eval = withUpdatedClassloader(file) {
- 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)
- }
- }
- val contracts = when (eval) {
- is Contract -> listOf(eval)
- is Iterable<*> -> eval.filterIsInstance(Contract::class.java)
- is Array<*> -> eval.filterIsInstance(Contract::class.java)
- else -> emptyList()
- }
+ override fun convertFrom(file: File): Collection {
+ val eval = withUpdatedClassloader(file) {
+ BasicJvmScriptingHost().eval(file.toScriptSource(), ScriptWithCurrentClasspathConfiguration(), null)
+ }
+ when (eval) {
+ is ResultWithDiagnostics.Success<*> -> {
+ val contracts = when (val parsedValue = ((eval.value as EvaluationResult).returnValue as ResultValue.Value).value) {
+ is Contract -> listOf(parsedValue)
+ is Iterable<*> -> parsedValue.filterIsInstance(Contract::class.java)
+ is Array<*> -> parsedValue.filterIsInstance(Contract::class.java)
+ else -> emptyList()
+ }
- return withName(file, contracts)
- }
+ return withName(file, contracts)
+ }
- private fun withName(file: File, contracts: Collection): Collection {
- val counter = AtomicInteger(0)
- return contracts.onEach { contract ->
- if (ObjectUtils.isEmpty(contract.name)) {
- contract.name = defaultContractName(file, contracts, counter.get())
- }
- counter.incrementAndGet()
- }
- }
+ else -> throw IllegalStateException("Failed to parse kotlin script due to ${(eval as ResultWithDiagnostics.Failure).reports}")
+ }
+ }
- private fun defaultContractName(file: File, contracts: Collection<*>, counter: Int): String {
- val lastIndexOfDot = file.name.lastIndexOf(".")
- val tillExtension = file.name.substring(0, lastIndexOfDot)
- return tillExtension + if (counter > 0 || contracts.size > 1) "_$counter" else ""
- }
+ private fun withName(file: File, contracts: Collection): Collection {
+ val counter = AtomicInteger(0)
+ return contracts.onEach { contract ->
+ if (ObjectUtils.isEmpty(contract.name)) {
+ contract.name = defaultContractName(file, contracts, counter.get())
+ }
+ counter.incrementAndGet()
+ }
+ }
- override fun convertTo(contract: Collection) = contract.toList()
+ private fun defaultContractName(file: File, contracts: Collection<*>, counter: Int): String {
+ val lastIndexOfDot = file.name.lastIndexOf(".")
+ val tillExtension = file.name.substring(0, lastIndexOfDot)
+ return tillExtension + if (counter > 0 || contracts.size > 1) "_$counter" else ""
+ }
- private fun withUpdatedClassloader(file: File, block: ClassLoader.() -> Any): Any {
- val currentClassLoader = Thread.currentThread().contextClassLoader
- try {
- val tempClassLoader = newInstance(arrayOf(file.parentFile.toURI().toURL()), currentClassLoader)
- Thread.currentThread().contextClassLoader = tempClassLoader
- return tempClassLoader.block()
- } finally {
- Thread.currentThread().contextClassLoader = currentClassLoader
- }
- }
-}
\ No newline at end of file
+ override fun convertTo(contract: Collection) = contract.toList()
+
+ private fun withUpdatedClassloader(file: File, block: ClassLoader.() -> Any): Any {
+ val currentClassLoader = Thread.currentThread().contextClassLoader
+ try {
+ val tempClassLoader = newInstance(arrayOf(file.parentFile.toURI().toURL()), currentClassLoader)
+ Thread.currentThread().contextClassLoader = tempClassLoader
+ return tempClassLoader.block()
+ } finally {
+ Thread.currentThread().contextClassLoader = currentClassLoader
+ }
+ }
+
+ class ScriptWithCurrentClasspathConfiguration : ScriptCompilationConfiguration(
+ {
+ jvm {
+ // Extract the whole classpath from context classloader and use it as dependencies
+ dependenciesFromCurrentContext(wholeClasspath = true)
+ }
+ }
+ )
+}
diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
index 54c11d2cee..5b0cc91043 100644
--- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
+++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
@@ -56,15 +56,6 @@
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- **/PluginUnitTest.java
-
-
-
org.apache.maven.plugins
maven-failsafe-plugin