[REPL] Stop old classpath calculation on the base classloader

The mechanism of the recursive classpath checking is intended
 for the "inner" scripting/REPL classloaders and should not touch
 anything beyond.
This commit is contained in:
Ilya Muradyan
2021-04-30 14:35:19 +02:00
committed by teamcityserver
parent 4608ca15eb
commit bab5d16001
3 changed files with 12 additions and 6 deletions
@@ -42,7 +42,7 @@ class BasicJvmReplEvaluator(val scriptEvaluator: ScriptEvaluator = BasicJvmScrip
}
if (lastSnippetClass != null) {
jvm {
baseClassLoader(lastSnippetClass.java.classLoader)
lastSnippetClassLoader(lastSnippetClass.java.classLoader)
}
}
}
@@ -119,13 +119,14 @@ fun KJvmCompiledScript.getOrCreateActualClassloader(evaluationConfiguration: Scr
val module = compiledModule
?: throw IllegalStateException("Illegal call sequence, actualClassloader should be set before calling function on the class without module")
val baseClassLoader = evaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]
val lastClassLoader = evaluationConfiguration[ScriptEvaluationConfiguration.jvm.lastSnippetClassLoader] ?: baseClassLoader
val classLoaderWithDeps =
if (evaluationConfiguration[ScriptEvaluationConfiguration.jvm.loadDependencies] == false) baseClassLoader
else makeClassLoaderFromDependencies(baseClassLoader)
else makeClassLoaderFromDependencies(baseClassLoader, lastClassLoader)
return module.createClassLoader(classLoaderWithDeps)
}
private fun CompiledScript.makeClassLoaderFromDependencies(baseClassLoader: ClassLoader?): ClassLoader? {
private fun CompiledScript.makeClassLoaderFromDependencies(baseClassLoader: ClassLoader?, lastClassLoader: ClassLoader?): ClassLoader? {
val processedScripts = mutableSetOf<CompiledScript>()
fun recursiveScriptsSeq(res: Sequence<CompiledScript>, script: CompiledScript): Sequence<CompiledScript> =
if (processedScripts.add(script)) script.otherScripts.asSequence().fold(res + script, ::recursiveScriptsSeq)
@@ -139,17 +140,17 @@ private fun CompiledScript.makeClassLoaderFromDependencies(baseClassLoader: Clas
val processedClasspathElements = mutableSetOf<URL>()
fun recursiveClassPath(res: Sequence<URL>, classLoader: ClassLoader?): Sequence<URL> =
when (classLoader) {
null -> res
null, baseClassLoader -> res
is DualClassLoader -> recursiveClassPath(res, classLoader.parent) +
recursiveClassPath(emptySequence(), classLoader.fallbackClassLoader)
is URLClassLoader -> recursiveClassPath(res + classLoader.urLs, classLoader.parent)
else -> recursiveClassPath(res, classLoader.parent)
}
recursiveClassPath(emptySequence(), baseClassLoader).forEach { processedClasspathElements.add(it) }
recursiveClassPath(emptySequence(), lastClassLoader).forEach { processedClasspathElements.add(it) }
val processedClassloaders = mutableSetOf<ClassLoader>()
return dependenciesWithConfigurations.fold(baseClassLoader) { parentClassLoader, (compilationConfiguration, scriptDependency) ->
return dependenciesWithConfigurations.fold(lastClassLoader) { parentClassLoader, (compilationConfiguration, scriptDependency) ->
when (scriptDependency) {
is JvmDependency -> {
scriptDependency.classpath.mapNotNull {
@@ -33,6 +33,11 @@ val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection
isTransient = true
)
/**
* Classloader of the last snippet (supposed to be used in REPL)
*/
val JvmScriptEvaluationConfigurationKeys.lastSnippetClassLoader by PropertiesCollection.key<ClassLoader?>(isTransient = true)
/**
* Load script dependencies before evaluation, true by default
* If false, it is assumed that the all dependencies will be provided via baseClassLoader