Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2f2ecba

Browse files
KingFalse方卓
authored and
方卓
committed
Initial commit
1 parent fc98df6 commit 2f2ecba

File tree

12 files changed

+402
-0
lines changed

12 files changed

+402
-0
lines changed

‎pom.xml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>2.2.5.RELEASE</version>
9+
</parent>
10+
<groupId>me.kagura</groupId>
11+
<artifactId>springboot-kotlin-dynamic-compiler</artifactId>
12+
<version>0.0.1-SNAPSHOT</version>
13+
<name>SpringBoot-Kotlin-Dynamic-Compiler</name>
14+
<description>SpringBoot-Kotlin-Dynamic-Compiler</description>
15+
16+
<properties>
17+
<java.version>1.8</java.version>
18+
<kotlin.version>1.3.61</kotlin.version>
19+
<skipTests>true</skipTests>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.springframework.boot</groupId>
25+
<artifactId>spring-boot-starter-web</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.fasterxml.jackson.module</groupId>
29+
<artifactId>jackson-module-kotlin</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>net.java.dev.jna</groupId>
33+
<artifactId>jna</artifactId>
34+
<version>5.5.0</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.jetbrains.kotlin</groupId>
38+
<artifactId>kotlin-compiler-embeddable</artifactId>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.jetbrains.kotlin</groupId>
42+
<artifactId>kotlin-scripting-compiler-embeddable</artifactId>
43+
<version>${kotlin.version}</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.jetbrains.kotlin</groupId>
47+
<artifactId>kotlin-script-util</artifactId>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.jetbrains.kotlin</groupId>
51+
<artifactId>kotlin-reflect</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.jetbrains.kotlin</groupId>
55+
<artifactId>kotlin-stdlib-jdk8</artifactId>
56+
</dependency>
57+
58+
<dependency>
59+
<groupId>org.springframework.boot</groupId>
60+
<artifactId>spring-boot-starter-test</artifactId>
61+
<scope>test</scope>
62+
<exclusions>
63+
<exclusion>
64+
<groupId>org.junit.vintage</groupId>
65+
<artifactId>junit-vintage-engine</artifactId>
66+
</exclusion>
67+
</exclusions>
68+
</dependency>
69+
</dependencies>
70+
71+
<build>
72+
<finalName>${pom.name}</finalName>
73+
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
74+
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
75+
<plugins>
76+
<plugin>
77+
<groupId>org.springframework.boot</groupId>
78+
<artifactId>spring-boot-maven-plugin</artifactId>
79+
</plugin>
80+
<plugin>
81+
<groupId>org.jetbrains.kotlin</groupId>
82+
<artifactId>kotlin-maven-plugin</artifactId>
83+
<configuration>
84+
<args>
85+
<arg>-Xjsr305=strict</arg>
86+
</args>
87+
<compilerPlugins>
88+
<plugin>spring</plugin>
89+
</compilerPlugins>
90+
</configuration>
91+
<dependencies>
92+
<dependency>
93+
<groupId>org.jetbrains.kotlin</groupId>
94+
<artifactId>kotlin-maven-allopen</artifactId>
95+
<version>${kotlin.version}</version>
96+
</dependency>
97+
</dependencies>
98+
</plugin>
99+
</plugins>
100+
</build>
101+
102+
</project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package me.kagura.dynamiccompiler
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication
4+
import org.springframework.boot.runApplication
5+
6+
@SpringBootApplication
7+
class SpringBootKotlinDynamicCompilerApplication
8+
9+
fun main(args: Array<String>) {
10+
runApplication<SpringBootKotlinDynamicCompilerApplication>(*args)
11+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package me.kagura.dynamiccompiler.compiler
2+
3+
import org.slf4j.LoggerFactory
4+
import java.io.File
5+
import java.net.URLClassLoader
6+
import java.nio.file.Files
7+
8+
class KotlinCompiler {
9+
10+
fun kotlinc(source: String): Class<*>? {
11+
val logger = LoggerFactory.getLogger("KotlinCompiler")
12+
val packageName = Regex("""package[ ]+([\w._\p{S}]+)""").find(source)?.groupValues?.get(1) ?: ""
13+
val className = Regex("""class[ ]+(\S*)""").find(source)?.groupValues?.get(1) ?: ""
14+
var canonicalName = ""
15+
if (packageName.isNotEmpty()) {
16+
canonicalName += "$packageName."
17+
}
18+
canonicalName += className
19+
20+
val kotlinDynamicCompiler = KotlinDynamicCompiler()
21+
22+
try {
23+
val outputDir = Files.createTempDirectory(System.currentTimeMillis().toString()).toFile()
24+
val key = "${System.currentTimeMillis()}"
25+
outputDir.absolutePath
26+
val ktFile = File(outputDir, "$key.kt")
27+
ktFile.writeText(source)
28+
kotlinDynamicCompiler.compileModule("", listOf(ktFile.absolutePath), outputDir, Thread.currentThread().contextClassLoader)
29+
val uri = arrayOf(outputDir.toURI().toURL())
30+
val classLoader = URLClassLoader.newInstance(uri)
31+
return classLoader.loadClass(canonicalName)
32+
} catch (e: Exception) {
33+
logger.error("Kotlin编译失败,source={}", source, e)
34+
e.printStackTrace()
35+
}
36+
return null
37+
}
38+
39+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package me.kagura.dynamiccompiler.compiler
2+
3+
import me.kagura.dynamiccompiler.utils.JAR_CLASS_PATH
4+
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
5+
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
6+
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
7+
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
8+
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
9+
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
10+
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
11+
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
12+
import org.jetbrains.kotlin.codegen.state.GenerationState
13+
import org.jetbrains.kotlin.com.intellij.openapi.Disposable
14+
import org.jetbrains.kotlin.config.CommonConfigurationKeys
15+
import org.jetbrains.kotlin.config.CompilerConfiguration
16+
import org.jetbrains.kotlin.config.JVMConfigurationKeys
17+
import org.jetbrains.kotlin.config.JvmTarget
18+
import org.slf4j.LoggerFactory
19+
import java.io.ByteArrayOutputStream
20+
import java.io.File
21+
import java.io.PrintStream
22+
import kotlin.script.experimental.jvm.util.KotlinJars
23+
import kotlin.script.experimental.jvm.util.classpathFromClassloader
24+
25+
class KotlinDynamicCompiler {
26+
fun compileModule(moduleName: String,
27+
sourcePath: List<String>,
28+
saveClassesDir: File,
29+
classLoader: ClassLoader? = null,
30+
forcedAddKotlinStd: Boolean = true
31+
32+
): GenerationState {
33+
val logger = LoggerFactory.getLogger("KotlinDynamicCompiler")
34+
val stubDisposable = StubDisposable()
35+
val configuration = CompilerConfiguration()
36+
configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
37+
val ps: PrintStream = PrintStream(ByteArrayOutputStream())
38+
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, PrintingMessageCollector(ps, MessageRenderer.PLAIN_FULL_PATHS, true))
39+
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir)
40+
//configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
41+
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
42+
val classPath = mutableSetOf<File>()
43+
if (classLoader != null) {
44+
classPath.addAll(classpathFromClassloader(classLoader)!!)
45+
}
46+
if (forcedAddKotlinStd) {
47+
classPath.add(KotlinJars.stdlib)
48+
}
49+
JAR_CLASS_PATH.forEach {
50+
classPath.add(it)
51+
}
52+
configuration.addJvmClasspathRoots(classPath.toList())
53+
configuration.addKotlinSourceRoots(sourcePath)
54+
val env = KotlinCoreEnvironment.createForProduction(stubDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
55+
val result = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(env)
56+
ps.flush()
57+
if (result != null) {
58+
return result
59+
} else {
60+
logger.info("kotlin编译异常")
61+
throw IllegalStateException("Compilation error. Details:\n$ps")
62+
}
63+
64+
}
65+
66+
inner class StubDisposable : Disposable {
67+
@Volatile
68+
var isDisposed: Boolean = false
69+
private set
70+
71+
override fun dispose() {
72+
isDisposed = true
73+
}
74+
75+
}
76+
77+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package me.kagura.dynamiccompiler.controller
2+
3+
import me.kagura.dynamiccompiler.compiler.KotlinCompiler
4+
import me.kagura.dynamiccompiler.script.Worker
5+
import org.springframework.web.bind.annotation.PostMapping
6+
import org.springframework.web.bind.annotation.RequestBody
7+
import org.springframework.web.bind.annotation.RestController
8+
9+
@RestController
10+
class ExecController {
11+
12+
@PostMapping("/exec")
13+
fun exec(@RequestBody source: String): String {
14+
val newInstance = KotlinCompiler().kotlinc(source)?.newInstance() ?: return "Compilation error."
15+
val worker = newInstance as Worker
16+
return worker.doWork()
17+
}
18+
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package me.kagura.dynamiccompiler.listener
2+
3+
import me.kagura.dynamiccompiler.utils.unJar
4+
import org.springframework.boot.context.event.ApplicationReadyEvent
5+
import org.springframework.context.ApplicationListener
6+
import org.springframework.stereotype.Component
7+
8+
@Component
9+
class InitClassPath : ApplicationListener<ApplicationReadyEvent> {
10+
override fun onApplicationEvent(p0: ApplicationReadyEvent) {
11+
unJar()
12+
}
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package me.kagura.dynamiccompiler.script
2+
3+
interface Worker {
4+
fun doWork(): String
5+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package me.kagura.dynamiccompiler.utils
2+
3+
import org.springframework.boot.system.ApplicationHome
4+
import java.io.File
5+
import java.nio.file.Files
6+
import java.util.jar.JarFile
7+
8+
var JAR_CLASS_PATH: Array<File> = emptyArray()
9+
10+
/**
11+
* 解压当前Jar包并拼接ClassPath
12+
*/
13+
fun unJar() {
14+
val tempDirectory = Files.createTempDirectory("").toFile()
15+
val source = ApplicationHome().source ?: return
16+
val jarFile = JarFile(source)
17+
jarFile.entries().asSequence().forEach {
18+
val tempFile = File(tempDirectory, it.name)
19+
if (it.isDirectory) {
20+
tempFile.mkdirs()
21+
} else {
22+
val inputStream = jarFile.getInputStream(it)
23+
Files.copy(inputStream, tempFile.toPath())
24+
}
25+
}
26+
jarFile.close()
27+
val lib = File(tempDirectory, "BOOT-INF${File.separator}lib")
28+
val classes = File(tempDirectory, "BOOT-INF${File.separator}classes")
29+
JAR_CLASS_PATH = lib.listFiles().plus(classes)
30+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<idea-plugin>
2+
<id>org.jetbrains.kotlin</id>
3+
<version>1.2</version>
4+
5+
<extensionPoints>
6+
<extensionPoint qualifiedName="org.jetbrains.kotlin.analyzeCompleteHandlerExtension"
7+
interface="org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension"
8+
area="IDEA_PROJECT"/>
9+
<extensionPoint qualifiedName="org.jetbrains.kotlin.callResolutionInterceptorExtension"
10+
interface="org.jetbrains.kotlin.extensions.CallResolutionInterceptorExtension"
11+
area="IDEA_PROJECT"/>
12+
<extensionPoint qualifiedName="org.jetbrains.kotlin.typeResolutionInterceptorExtension"
13+
interface="org.jetbrains.kotlin.extensions.TypeResolutionInterceptorExtension"
14+
area="IDEA_PROJECT"/>
15+
<extensionPoint qualifiedName="org.jetbrains.kotlin.diagnosticSuppressor"
16+
interface="org.jetbrains.kotlin.resolve.diagnostics.DiagnosticSuppressor"/>
17+
<extensionPoint qualifiedName="org.jetbrains.kotlin.expressionCodegenExtension"
18+
interface="org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension"
19+
area="IDEA_PROJECT"/>
20+
<extensionPoint qualifiedName="org.jetbrains.kotlin.syntheticResolveExtension"
21+
interface="org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension"
22+
area="IDEA_PROJECT"/>
23+
<extensionPoint qualifiedName="org.jetbrains.kotlin.jsSyntheticTranslateExtension"
24+
interface="org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension"
25+
area="IDEA_PROJECT"/>
26+
<extensionPoint qualifiedName="org.jetbrains.kotlin.irGenerationExtension"
27+
interface="org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension"
28+
area="IDEA_PROJECT"/>
29+
<extensionPoint qualifiedName="org.jetbrains.kotlin.simpleNameReferenceExtension"
30+
interface="org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension"
31+
area="IDEA_PROJECT"/>
32+
<extensionPoint qualifiedName="org.jetbrains.kotlin.kotlinIndicesHelperExtension"
33+
interface="org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension"
34+
area="IDEA_PROJECT"/>
35+
<extensionPoint qualifiedName="org.jetbrains.kotlin.classBuilderFactoryInterceptorExtension"
36+
interface="org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension"
37+
area="IDEA_PROJECT"/>
38+
<extensionPoint qualifiedName="org.jetbrains.kotlin.packageFragmentProviderExtension"
39+
interface="org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension"
40+
area="IDEA_PROJECT"/>
41+
<extensionPoint qualifiedName="org.jetbrains.kotlin.quickFixContributor"
42+
interface="org.jetbrains.kotlin.idea.quickfix.QuickFixContributor"/>
43+
<extensionPoint qualifiedName="org.jetbrains.kotlin.storageComponentContainerContributor"
44+
interface="org.jetbrains.kotlin.extensions.StorageComponentContainerContributor"
45+
area="IDEA_PROJECT"/>
46+
<extensionPoint qualifiedName="org.jetbrains.kotlin.scriptDefinitionContributor"
47+
interface="org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor"
48+
area="IDEA_PROJECT"/>
49+
<extensionPoint qualifiedName="org.jetbrains.kotlin.scriptTemplatesProvider"
50+
interface="org.jetbrains.kotlin.script.ScriptTemplatesProvider"
51+
area="IDEA_PROJECT"/>
52+
<extensionPoint qualifiedName="org.jetbrains.kotlin.extraImportsProviderExtension"
53+
interface="org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension"
54+
area="IDEA_PROJECT"/>
55+
<extensionPoint qualifiedName="org.jetbrains.kotlin.facetConfigurationExtension"
56+
interface="org.jetbrains.kotlin.idea.facet.KotlinFacetConfigurationExtension"/>
57+
<extensionPoint qualifiedName="org.jetbrains.kotlin.versionInfoProvider"
58+
interface="org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProvider"/>
59+
<extensionPoint qualifiedName="org.jetbrains.kotlin.completionInformationProvider"
60+
interface="org.jetbrains.kotlin.idea.completion.CompletionInformationProvider" />
61+
<extensionPoint qualifiedName="org.jetbrains.kotlin.moduleBuilder"
62+
interface="com.intellij.ide.util.projectWizard.ModuleBuilder"/>
63+
<extensionPoint qualifiedName="org.jetbrains.kotlin.renameHandler"
64+
interface="com.intellij.refactoring.rename.RenameHandler"/>
65+
</extensionPoints>
66+
</idea-plugin>

‎src/main/resources/application.properties

Whitespace-only changes.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /