Fix plugin's dependencies classes linking; fix #2054

This commit is contained in:
Karlatemp 2022-05-24 17:56:29 +08:00
parent e25e604c79
commit 48c2b04a49
No known key found for this signature in database
GPG Key ID: BA173CA2B9956C59
14 changed files with 163 additions and 17 deletions

View File

@ -0,0 +1 @@
net.mamoe.consoleit.issue2054:moda:1.0.0

View File

@ -0,0 +1,16 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package issue2054.modulea
public object ModuleA {
public fun act(b: () -> Unit) {
b()
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("UnusedImport")
plugins {
kotlin("jvm")
kotlin("plugin.serialization")
id("java")
}
version = "0.0.0"
kotlin {
explicitApiWarning()
}
dependencies {
api(project(":mirai-console.integration-test"))
api(parent!!.project("module-moda"))
}

View File

@ -0,0 +1 @@
net.mamoe.consoleit.issue2054:modb:1.0.0

View File

@ -0,0 +1,20 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package issue2054.moduleb
import issue2054.modulea.ModuleA
public object ModuleB {
public val getModuleA: Any get() = ModuleA
public fun act(b: () -> Unit) {
b()
}
}

View File

@ -0,0 +1,10 @@
#
# Copyright 2019-2022 Mamoe Technologies and contributors.
#
# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
#
# https://github.com/mamoe/mirai/blob/dev/LICENSE
#
pdepdep2054.PDepDependOnDep

View File

@ -0,0 +1,10 @@
#
# Copyright 2019-2022 Mamoe Technologies and contributors.
#
# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
#
# https://github.com/mamoe/mirai/blob/dev/LICENSE
#
pdepdep2054sec.PDepDependOnDepSec

View File

@ -0,0 +1,35 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package pdepdep2054sec
import issue2054.modulea.ModuleA
import issue2054.moduleb.ModuleB
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import net.mamoe.mirai.utils.info
import kotlin.test.assertSame
public object PDepDependOnDepSec : KotlinPlugin(
JvmPluginDescription("net.mamoe.console.itest.plugin-dep-dependon-dep-sec", "0.0.0") {
dependsOn("net.mamoe.console.itest.plugin-dep-dependon-dep")
}
) {
override fun onEnable() {
jvmPluginClasspath.downloadAndAddToPath(
jvmPluginClasspath.pluginIndependentLibrariesClassLoader,
listOf("net.mamoe.consoleit.issue2054:modb:1.0.0")
)
assertSame(ModuleA, ModuleB.getModuleA)
logger.info { "issue 2054" }
ModuleB.act { ModuleA.act { logger.info(Throwable("Stack trace")) } }
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package pdepdep2054
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
public object PDepDependOnDep : KotlinPlugin(
JvmPluginDescription("net.mamoe.console.itest.plugin-dep-dependon-dep", "0.0.0")
) {
init {
jvmPluginClasspath.downloadAndAddToPath(
jvmPluginClasspath.pluginSharedLibrariesClassLoader,
listOf("net.mamoe.consoleit.issue2054:moda:1.0.0")
)
}
}

View File

@ -245,6 +245,9 @@ internal class BuiltInJvmPluginLoaderImpl(
}.mapNotNull { it.javaClass.classLoader.safeCast<JvmPluginClassLoaderN>() }.forEach { dependency ->
plugin.logger.debug { "Linked dependency: $dependency" }
jvmPluginClassLoaderN.dependencies.add(dependency)
jvmPluginClassLoaderN.pluginSharedCL.dependencies.cast<MutableList<DynLibClassLoader>>().add(
dependency.pluginSharedCL
)
}
jvmPluginClassLoaderN.linkPluginLibraries(plugin.logger)
}

View File

@ -54,6 +54,7 @@ internal class JvmPluginsLoadingCtx(
internal class DynLibClassLoader : URLClassLoader {
private val clName: String?
internal var dependencies: List<DynLibClassLoader> = emptyList()
private constructor(parent: ClassLoader?, clName: String?) : super(arrayOf(), parent) {
this.clName = clName
@ -140,13 +141,22 @@ internal class DynLibClassLoader : URLClassLoader {
}
}
internal fun findButNoSystem(name: String): Class<*>? {
internal fun findButNoSystem(name: String): Class<*>? = findButNoSystem(name, mutableListOf())
private fun findButNoSystem(name: String, track: MutableList<DynLibClassLoader>): Class<*>? {
if (name.startsWith("java.")) return null
// Skip duplicated searching, for faster speed.
if (this in track) return null
track.add(this)
val pt = this.parent
if (pt is DynLibClassLoader) {
pt.findButNoSystem(name)?.let { return it }
pt.findButNoSystem(name, track)?.let { return it }
}
dependencies.forEach { dep ->
dep.findButNoSystem(name, track)?.let { return it }
}
synchronized(getClassLoadingLock(name)) {
findLoadedClass(name)?.let { return it }
try {
@ -160,22 +170,10 @@ internal class DynLibClassLoader : URLClassLoader {
override fun loadClass(name: String, resolve: Boolean): Class<*> {
tryFastOrStrictResolve(name)?.let { return it }
val pt = this.parent
val topPt: ClassLoader? = if (pt is DynLibClassLoader) {
pt.findButNoSystem(name)?.let { return it }
findButNoSystem(name)?.let { return it }
generateSequence<ClassLoader>(pt) { it.parent }.firstOrNull { it !is DynLibClassLoader }
} else pt
synchronized(getClassLoadingLock(name)) {
findLoadedClass(name)?.let { return it }
try {
return findClass(name)
} catch (ignored: ClassNotFoundException) {
}
return Class.forName(name, false, topPt)
}
val topParent = generateSequence<ClassLoader>(this) { it.parent }.firstOrNull { it !is DynLibClassLoader }
return Class.forName(name, false, topParent)
}
}
@ -236,6 +234,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
pluginIndependentCL = DynLibClassLoader.newInstance(
pluginSharedCL, "IndependentCL{${file.name}}", "${file.name}[private]"
)
pluginSharedCL.dependencies = mutableListOf()
addURL(file.toURI().toURL())
}