diff --git a/build-tools-gradle-test/build.gradle.kts b/build-tools-gradle-test/build.gradle.kts index 0a23c27..14eb769 100644 --- a/build-tools-gradle-test/build.gradle.kts +++ b/build-tools-gradle-test/build.gradle.kts @@ -39,8 +39,9 @@ mpsBuild { } runMPS("runLambdaInMPS") { + val variableOutsideTheLambda = "a" implementation { - println("Lambda invoked") + println("Lambda invoked: $variableOutsideTheLambda") } } } diff --git a/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/InvokeLambda.kt b/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/InvokeLambda.kt index e686116..ec860c1 100644 --- a/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/InvokeLambda.kt +++ b/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/InvokeLambda.kt @@ -1,16 +1,17 @@ package org.modelix.gradle.mpsbuild +import java.io.FileInputStream +import java.io.ObjectInputStream + object InvokeLambda { - const val PROPERTY_KEY = "runMPS.lambda.name" + const val PROPERTY_KEY = "runMPS.lambda.file" @JvmStatic fun invoke() { - // System.getProperty(PROPERTY_KEY) would get instrumented which introduces a Gradle dependency - val lambdaName = System::class.java.getMethod("getProperty", String::class.java) - .invoke(null, PROPERTY_KEY) as String - val cls = Class.forName(lambdaName) - val lambdaInstance = cls.getField("INSTANCE").also { it.trySetAccessible() } - .get(null) as () -> Unit + val lambdaFileName = System.getProperty(PROPERTY_KEY) + val lambdaInstance = ObjectInputStream(FileInputStream(lambdaFileName)).use { + it.readObject() as () -> Unit + } lambdaInstance() } } \ No newline at end of file diff --git a/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/MPSBuildPlugin.kt b/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/MPSBuildPlugin.kt index b774dbb..364113a 100644 --- a/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/MPSBuildPlugin.kt +++ b/build-tools-gradle/src/main/kotlin/org/modelix/gradle/mpsbuild/MPSBuildPlugin.kt @@ -43,6 +43,7 @@ import org.modelix.buildtools.runner.MPSRunner import org.modelix.buildtools.xmlToString import org.zeroturnaround.zip.ZipUtil import java.io.File +import java.io.ObjectOutputStream import java.nio.file.Path import java.nio.file.Paths import java.text.SimpleDateFormat @@ -411,14 +412,18 @@ class MPSBuildPlugin : Plugin { val exportImplTask: TaskProvider? = if (mainMethodImpl != null) { val implJarFile = workDir.resolve(entry.key + "-impl.jar") val implClass = mainMethodImpl::class.java + val serializedLambdaFile = workDir.resolve(entry.key + "-impl.obj") runnerConfig = runnerConfig.copy( classPathElements = runnerConfig.classPathElements + implJarFile, mainClassName = InvokeLambda::class.java.name, mainMethodName = InvokeLambda::invoke.name, - jvmArgs = runnerConfig.jvmArgs + "-D${InvokeLambda.PROPERTY_KEY}=${implClass.name}" + jvmArgs = runnerConfig.jvmArgs + "-D${InvokeLambda.PROPERTY_KEY}=${serializedLambdaFile.absolutePath}" ) project.tasks.register(entry.key + "_exportImpl") { doLast { + ObjectOutputStream(serializedLambdaFile.outputStream()).use { + it.writeObject(mainMethodImpl) + } ZipOutputStream(implJarFile.outputStream()).use { zos -> for (cls in listOf(implClass, InvokeLambda::class.java)) { zos.putNextEntry(ZipEntry(cls.getResourceName().trimStart('/'))) @@ -704,9 +709,17 @@ class MPSBuildPlugin : Plugin { private fun String.firstLetterUppercase() = if (isEmpty()) this else substring(0, 1).toUpperCase() + drop(1) private fun Class<*>.readClassBytes(): ByteArray { + // Try to get the non-instrumented original class file first + val classLoaders = generateSequence(classLoader) { it.parent } + for (currentLoader in classLoaders.toList().asReversed()) { + val resource = currentLoader.getResource(getResourceName()) ?: continue + return resource.readBytes() + } + val resource = getResource(getResourceName()) ?: throw RuntimeException("Resource ${getResourceName()} not found in $classLoader") return resource.readBytes() + } private fun Class<*>.getResourceName() = "/${name.replace(".", "/")}.class"