Allow explicit nulls for props with default, allow null as base classloader for evaluation
and use proper default evaluation configuration if not supplied explicitly; also add reset method to the properties builder and containsKey method to the properties collection #KT-29296 fixed
This commit is contained in:
+14
-6
@@ -11,7 +11,7 @@ import kotlin.reflect.KProperty
|
|||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.script.experimental.api.KotlinType
|
import kotlin.script.experimental.api.KotlinType
|
||||||
|
|
||||||
open class PropertiesCollection(private val properties: Map<Key<*>, Any> = emptyMap()) : Serializable {
|
open class PropertiesCollection(private val properties: Map<Key<*>, Any?> = emptyMap()) : Serializable {
|
||||||
|
|
||||||
class Key<T>(val name: String, @Transient val defaultValue: T? = null) : Serializable {
|
class Key<T>(val name: String, @Transient val defaultValue: T? = null) : Serializable {
|
||||||
|
|
||||||
@@ -36,13 +36,17 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any> = empty
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
operator fun <T> get(key: PropertiesCollection.Key<T>): T? =
|
operator fun <T> get(key: PropertiesCollection.Key<T>): T? =
|
||||||
properties[key]?.let { it as T } ?: key.defaultValue
|
if (key.defaultValue == null) properties[key] as T?
|
||||||
|
else properties.getOrDefault(key, key.defaultValue) as T?
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T> getNoDefault(key: PropertiesCollection.Key<T>): T? =
|
fun <T> getNoDefault(key: PropertiesCollection.Key<T>): T? =
|
||||||
properties[key]?.let { it as T }
|
properties[key]?.let { it as T }
|
||||||
|
|
||||||
fun entries(): Set<Map.Entry<Key<*>, Any>> = properties.entries
|
fun <T> containsKey(key: PropertiesCollection.Key<T>): Boolean =
|
||||||
|
properties.containsKey(key)
|
||||||
|
|
||||||
|
fun entries(): Set<Map.Entry<Key<*>, Any?>> = properties.entries
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun <T> key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue)
|
fun <T> key(defaultValue: T? = null) = PropertyKeyDelegate(defaultValue)
|
||||||
@@ -56,13 +60,13 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any> = empty
|
|||||||
|
|
||||||
open class Builder(baseProperties: Iterable<PropertiesCollection> = emptyList()) {
|
open class Builder(baseProperties: Iterable<PropertiesCollection> = emptyList()) {
|
||||||
|
|
||||||
val data: MutableMap<PropertiesCollection.Key<*>, Any> = LinkedHashMap<PropertiesCollection.Key<*>, Any>().apply {
|
val data: MutableMap<PropertiesCollection.Key<*>, Any?> = LinkedHashMap<PropertiesCollection.Key<*>, Any?>().apply {
|
||||||
baseProperties.forEach { putAll(it.properties) }
|
baseProperties.forEach { putAll(it.properties) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic for all properties
|
// generic for all properties
|
||||||
|
|
||||||
operator fun <T : Any> PropertiesCollection.Key<T>.invoke(v: T) {
|
operator fun <T> PropertiesCollection.Key<T>.invoke(v: T) {
|
||||||
data[this] = v
|
data[this] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,10 +141,14 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any> = empty
|
|||||||
|
|
||||||
// direct manipulation - public - for usage in inline dsl methods and for extending dsl
|
// direct manipulation - public - for usage in inline dsl methods and for extending dsl
|
||||||
|
|
||||||
operator fun <T : Any> set(key: PropertiesCollection.Key<in T>, value: T) {
|
operator fun <T> set(key: PropertiesCollection.Key<in T>, value: T) {
|
||||||
data[key] = value
|
data[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> reset(key: PropertiesCollection.Key<in T>) {
|
||||||
|
data.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
operator fun <T : Any> get(key: PropertiesCollection.Key<in T>): T? = data[key]?.let { it as T }
|
operator fun <T : Any> get(key: PropertiesCollection.Key<in T>): T? = data[key]?.let { it as T }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import java.io.InputStream
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class CompiledScriptClassLoader(parent: ClassLoader, private val entries: Map<String, ByteArray>) : ClassLoader(parent) {
|
internal class CompiledScriptClassLoader(parent: ClassLoader?, private val entries: Map<String, ByteArray>) : ClassLoader(parent) {
|
||||||
|
|
||||||
override fun findClass(name: String): Class<*>? {
|
override fun findClass(name: String): Class<*>? {
|
||||||
val classPathName = name.replace('.', '/') + ".class"
|
val classPathName = name.replace('.', '/') + ".class"
|
||||||
|
|||||||
+8
-7
@@ -13,9 +13,7 @@ import java.net.URLClassLoader
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.jvm.JvmDependency
|
import kotlin.script.experimental.jvm.JvmDependency
|
||||||
import kotlin.script.experimental.jvmhost.JvmScriptEvaluationConfiguration
|
import kotlin.script.experimental.jvmhost.*
|
||||||
import kotlin.script.experimental.jvmhost.actualClassLoader
|
|
||||||
import kotlin.script.experimental.jvmhost.baseClassLoader
|
|
||||||
|
|
||||||
class KJvmCompiledModule(
|
class KJvmCompiledModule(
|
||||||
generationState: GenerationState
|
generationState: GenerationState
|
||||||
@@ -54,12 +52,15 @@ class KJvmCompiledScript<out ScriptBase : Any>(
|
|||||||
get() = _otherScripts
|
get() = _otherScripts
|
||||||
|
|
||||||
override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>> = try {
|
override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>> = try {
|
||||||
val classLoader = scriptEvaluationConfiguration?.get(JvmScriptEvaluationConfiguration.actualClassLoader)
|
// ensuring proper defaults are used
|
||||||
|
val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||||
|
val classLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.actualClassLoader]
|
||||||
?: run {
|
?: run {
|
||||||
if (compiledModule == null)
|
if (compiledModule == null)
|
||||||
return ResultWithDiagnostics.Failure("Unable to load class $scriptClassFQName: no compiled module is provided".asErrorDiagnostics(path = sourceLocationId))
|
return ResultWithDiagnostics.Failure(
|
||||||
val baseClassLoader = scriptEvaluationConfiguration?.get(JvmScriptEvaluationConfiguration.baseClassLoader)
|
"Unable to load class $scriptClassFQName: no compiled module is provided".asErrorDiagnostics(path = sourceLocationId)
|
||||||
?: Thread.currentThread().contextClassLoader
|
)
|
||||||
|
val baseClassLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]
|
||||||
val dependencies = compilationConfiguration[ScriptCompilationConfiguration.dependencies]
|
val dependencies = compilationConfiguration[ScriptCompilationConfiguration.dependencies]
|
||||||
?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() }
|
?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() }
|
||||||
// TODO: previous dependencies and classloaders should be taken into account here
|
// TODO: previous dependencies and classloaders should be taken into account here
|
||||||
|
|||||||
+18
-20
@@ -10,16 +10,18 @@ package kotlin.script.experimental.jvmhost
|
|||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.util.PropertiesCollection
|
import kotlin.script.experimental.util.PropertiesCollection
|
||||||
|
|
||||||
open class JvmScriptEvaluationConfiguration : PropertiesCollection.Builder() {
|
interface JvmScriptEvaluationConfigurationKeys
|
||||||
|
|
||||||
companion object : JvmScriptEvaluationConfiguration()
|
open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builder(), JvmScriptEvaluationConfigurationKeys {
|
||||||
|
|
||||||
|
companion object : JvmScriptEvaluationConfigurationBuilder()
|
||||||
}
|
}
|
||||||
|
|
||||||
val JvmScriptEvaluationConfiguration.baseClassLoader by PropertiesCollection.key<ClassLoader?>(Thread.currentThread().contextClassLoader)
|
val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key<ClassLoader?>(Thread.currentThread().contextClassLoader)
|
||||||
|
|
||||||
val JvmScriptEvaluationConfiguration.actualClassLoader by PropertiesCollection.key<ClassLoader?>()
|
val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key<ClassLoader?>()
|
||||||
|
|
||||||
val ScriptEvaluationConfiguration.jvm get() = JvmScriptEvaluationConfiguration()
|
val ScriptEvaluationConfigurationKeys.jvm get() = JvmScriptEvaluationConfigurationBuilder()
|
||||||
|
|
||||||
open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
||||||
|
|
||||||
@@ -28,27 +30,23 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
|||||||
scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
|
scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
|
||||||
): ResultWithDiagnostics<EvaluationResult> =
|
): ResultWithDiagnostics<EvaluationResult> =
|
||||||
try {
|
try {
|
||||||
compiledScript.getClass(scriptEvaluationConfiguration).onSuccess { scriptClass ->
|
val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||||
|
compiledScript.getClass(actualEvaluationConfiguration).onSuccess { scriptClass ->
|
||||||
// in the future, when (if) we'll stop to compile everything into constructor
|
// in the future, when (if) we'll stop to compile everything into constructor
|
||||||
// run as SAM
|
// run as SAM
|
||||||
// return res
|
// return res
|
||||||
|
|
||||||
// for other scripts we need evaluation configuration with actualClassloader set,
|
// for other scripts we need evaluation configuration with actualClassloader set,
|
||||||
// so they are loaded in the same classloader as the "main" script
|
// so they are loaded in the same classloader as the "main" script
|
||||||
val updatedEvalConfiguration = when {
|
val updatedEvalConfiguration =
|
||||||
scriptEvaluationConfiguration == null -> ScriptEvaluationConfiguration {
|
if (actualEvaluationConfiguration.containsKey(ScriptEvaluationConfiguration.jvm.actualClassLoader))
|
||||||
// TODO: find out why dsl syntax doesn't work here
|
actualEvaluationConfiguration
|
||||||
set(JvmScriptEvaluationConfiguration.actualClassLoader, scriptClass.java.classLoader)
|
else
|
||||||
}
|
ScriptEvaluationConfiguration(actualEvaluationConfiguration) {
|
||||||
scriptEvaluationConfiguration.getNoDefault(JvmScriptEvaluationConfiguration.actualClassLoader) == null ->
|
ScriptEvaluationConfiguration.jvm.actualClassLoader(scriptClass.java.classLoader)
|
||||||
ScriptEvaluationConfiguration(scriptEvaluationConfiguration) {
|
|
||||||
// TODO: find out why dsl syntax doesn't work here
|
|
||||||
set(JvmScriptEvaluationConfiguration.actualClassLoader, scriptClass.java.classLoader)
|
|
||||||
}
|
}
|
||||||
else -> scriptEvaluationConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
val sharedScripts = scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.scriptsInstancesSharingMap)
|
val sharedScripts = actualEvaluationConfiguration[ScriptEvaluationConfiguration.scriptsInstancesSharingMap]
|
||||||
|
|
||||||
val instanceFromShared = sharedScripts?.get(scriptClass)
|
val instanceFromShared = sharedScripts?.get(scriptClass)
|
||||||
|
|
||||||
@@ -61,10 +59,10 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
|||||||
updatedEvalConfiguration[ScriptEvaluationConfiguration.constructorArgs]?.let {
|
updatedEvalConfiguration[ScriptEvaluationConfiguration.constructorArgs]?.let {
|
||||||
args.addAll(it)
|
args.addAll(it)
|
||||||
}
|
}
|
||||||
scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.providedProperties)?.forEach {
|
actualEvaluationConfiguration[ScriptEvaluationConfiguration.providedProperties]?.forEach {
|
||||||
args.add(it.value)
|
args.add(it.value)
|
||||||
}
|
}
|
||||||
scriptEvaluationConfiguration?.get(ScriptEvaluationConfiguration.implicitReceivers)?.let {
|
actualEvaluationConfiguration[ScriptEvaluationConfiguration.implicitReceivers]?.let {
|
||||||
args.addAll(it)
|
args.addAll(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user