From f434b5fa13968060f6f1c54d429cda3b286df833 Mon Sep 17 00:00:00 2001 From: nekkiy Date: Thu, 21 Nov 2019 16:59:16 +0300 Subject: [PATCH] [imp-AddKotlinDynamicCompiler] add kotlin compiler (#4544) --- modules/openapi-generator/pom.xml | 19 ++++ .../codegen/kotlin/KotlinTestUtils.java | 104 ++++++++++++++++++ .../codegen/kotlin/KotlinTestUtilsTest.java | 26 +++++ .../badPack/com/example/SimpleClass.kt | 8 ++ .../normalPack/com/example/SimpleClass.kt | 7 ++ 5 files changed, 164 insertions(+) create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtils.java create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtilsTest.java create mode 100644 modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/badPack/com/example/SimpleClass.kt create mode 100644 modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/normalPack/com/example/SimpleClass.kt diff --git a/modules/openapi-generator/pom.xml b/modules/openapi-generator/pom.xml index 25827d1793b..a60ebba1429 100644 --- a/modules/openapi-generator/pom.xml +++ b/modules/openapi-generator/pom.xml @@ -200,6 +200,7 @@ 1.0.2 2.9.10 2.9.10 + 1.3.41 @@ -328,6 +329,24 @@ openapi-generator-core ${project.parent.version} + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin-version} + test + + + org.jetbrains.kotlin + kotlin-compiler-embeddable + ${kotlin-version} + test + + + org.jetbrains.kotlin + kotlin-script-util + ${kotlin-version} + test + diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtils.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtils.java new file mode 100644 index 00000000000..4f43823c193 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtils.java @@ -0,0 +1,104 @@ +package org.openapitools.codegen.kotlin; + +import kotlin.script.experimental.jvm.util.KotlinJars; +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys; +import org.jetbrains.kotlin.cli.common.config.ContentRootsKt; +import org.jetbrains.kotlin.cli.common.messages.MessageRenderer; +import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector; +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler; +import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt; +import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.com.intellij.openapi.Disposable; +import org.jetbrains.kotlin.config.CommonConfigurationKeys; +import org.jetbrains.kotlin.config.CompilerConfiguration; +import org.jetbrains.kotlin.config.JVMConfigurationKeys; +import org.jetbrains.kotlin.config.JvmTarget; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.*; + +import static kotlin.script.experimental.jvm.util.JvmClasspathUtilKt.classpathFromClassloader; + +public class KotlinTestUtils { + + public static ClassLoader buildModule(List sourcePath, ClassLoader classLoader) { + + String moduleName = UUID.randomUUID().toString().replaceAll("-", ""); + File saveClassesDir; + try { + saveClassesDir = Files.createTempDirectory("kotlin" + moduleName).toFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + compileModule(moduleName, sourcePath, saveClassesDir, classLoader, true); + + try { + return new URLClassLoader(new URL[]{saveClassesDir.toURI().toURL()}, classLoader); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + } + + private static GenerationState compileModule(String moduleName, List sourcePath, File saveClassesDir, ClassLoader classLoader, boolean forcedAddKotlinStd) { + Disposable stubDisposable = new StubDisposable(); + CompilerConfiguration configuration = new CompilerConfiguration(); + configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = null; + try { + ps = new PrintStream(baos, true, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, new PrintingMessageCollector(ps, MessageRenderer.PLAIN_FULL_PATHS, true)); + configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir); +// configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8); + Set classPath = new HashSet<>(); + if (classLoader != null) { + classPath.addAll(classpathFromClassloader(classLoader, false)); + } + if (forcedAddKotlinStd) { + classPath.add(KotlinJars.INSTANCE.getStdlib()); + } + JvmContentRootsKt.addJvmClasspathRoots(configuration, new ArrayList<>(classPath)); + ContentRootsKt.addKotlinSourceRoots(configuration, sourcePath); + + KotlinCoreEnvironment env = KotlinCoreEnvironment.createForProduction(stubDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); + GenerationState result = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(env); + ps.flush(); + if (result != null) { + return result; + } else { + String s; + try { + s = new String(baos.toByteArray(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + throw new IllegalStateException("Compilation error. Details:\n" + s); + } + } + + static class StubDisposable implements Disposable { + + volatile boolean isDisposed = false; + + @Override + public void dispose() { + isDisposed = true; + } + + public boolean isDisposed() { + return isDisposed; + } + } +} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtilsTest.java new file mode 100644 index 00000000000..6aa8211a9a1 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/KotlinTestUtilsTest.java @@ -0,0 +1,26 @@ +package org.openapitools.codegen.kotlin; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.lang.reflect.Constructor; +import java.util.Collections; + +public class KotlinTestUtilsTest { + + @Test + public void testNormalCompile() throws Exception { + ClassLoader classLoader = KotlinTestUtils.buildModule(Collections.singletonList(getClass().getResource("KotlinTestUtilsTest/normalPack").getFile()), Thread.currentThread().getContextClassLoader()); + Class clazz = classLoader.loadClass("com.example.SimpleClass"); + Constructor[] constructors = clazz.getConstructors(); + Assert.assertEquals(1, constructors.length); + Constructor constr = constructors[0]; + Object testObj = constr.newInstance("test"); + } + + @Test(expectedExceptions = Exception.class) + public void testBadCompile() { + KotlinTestUtils.buildModule(Collections.singletonList(getClass().getResource("KotlinTestUtilsTest/badPack").getFile()), Thread.currentThread().getContextClassLoader()); + } + +} diff --git a/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/badPack/com/example/SimpleClass.kt b/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/badPack/com/example/SimpleClass.kt new file mode 100644 index 00000000000..92305471500 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/badPack/com/example/SimpleClass.kt @@ -0,0 +1,8 @@ +package com.example + + +class SimpleClass { + fun void testFun(){ + + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/normalPack/com/example/SimpleClass.kt b/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/normalPack/com/example/SimpleClass.kt new file mode 100644 index 00000000000..3243ef2bf08 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/org/openapitools/codegen/kotlin/KotlinTestUtilsTest/normalPack/com/example/SimpleClass.kt @@ -0,0 +1,7 @@ +package com.example + +class SimpleClass (val someStr:String) { + fun testFun(str: String) { + + } +} \ No newline at end of file