mirror of
https://github.com/mamoe/mirai.git
synced 2024-12-28 17:40:09 +08:00
修复JvmPlugin无法通过自己的classLoader以getResource的方法获取全局依赖的class文件 (#2536)
* [console] Fixed classLoaders of JvmPlugin cannot getResource(classes of global dependencies), fix #2535 * [core/utils/jvm] new fun: addAll(Enumeration) * [console] modify DynLibClassLoader.tryFastOrStrictResolveResource to tryFastOrStrictResolveResources * [console] remove allClassesAsResources field * [console] add var to control whether class files of mirai dependencies could be load as resources * [console/integration-test] modify loader test * [console] dump new apis * [console] rename JvmPluginClasspath.openMiraiDependenciesClassResource and standardize its KDoc * [console] modify the KDoc of JvmPluginClasspath.shouldResolveConsoleSystemResource * [console/integration-test] improve resources loading test cases * [console/integration-test] modify assert to assertTrue
This commit is contained in:
parent
3ff2737b3c
commit
4f0f733f4d
@ -17,6 +17,7 @@ import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
internal class PS : ServiceTypedef
|
||||
@ -64,7 +65,45 @@ internal object PMain : KotlinPlugin(JvmPluginDescription("net.mamoe.console.ite
|
||||
println(it)
|
||||
}.size
|
||||
)
|
||||
assertNull(javaClass.getResource("/net/mamoe/mirai/console/MiraiConsole.class"))
|
||||
assertNull(javaClass.getResource("/net/mamoe/mirai/Bot.class"))
|
||||
|
||||
// ************************* resources loading tests *************************
|
||||
|
||||
val miraiConsoleClassPath = "net/mamoe/mirai/console/MiraiConsole.class"
|
||||
val miraiBotClassPath = "net/mamoe/mirai/Bot.class"
|
||||
val allClassesPath = "META-INF/mirai-console/allclasses.txt"
|
||||
|
||||
fun ClassLoader.getSizeOfResources(path: String): Int {
|
||||
return this.getResources(path).toList().size
|
||||
}
|
||||
|
||||
assertNull(javaClass.getResource("/$miraiConsoleClassPath"))
|
||||
assertNull(javaClass.classLoader.getResource(miraiConsoleClassPath))
|
||||
val miraiConsoleClassResourceCount = javaClass.classLoader.getSizeOfResources(miraiConsoleClassPath)
|
||||
.also { assertEquals(0, it) }
|
||||
|
||||
assertNull(javaClass.getResource("/$miraiBotClassPath"))
|
||||
assertNull(javaClass.classLoader.getResource(miraiBotClassPath))
|
||||
|
||||
val allClassesResourceCount = javaClass.classLoader.getSizeOfResources(allClassesPath)
|
||||
.also { assertEquals(0, it) }
|
||||
|
||||
jvmPluginClasspath.shouldResolveConsoleSystemResource = true
|
||||
|
||||
assertNotNull(javaClass.classLoader.getResource(miraiConsoleClassPath))
|
||||
assertNotNull(javaClass.classLoader.getResource(miraiBotClassPath))
|
||||
|
||||
assertTrue(javaClass.classLoader.getSizeOfResources(miraiConsoleClassPath) > miraiConsoleClassResourceCount)
|
||||
assertTrue(javaClass.classLoader.getSizeOfResources(allClassesPath) > allClassesResourceCount)
|
||||
|
||||
jvmPluginClasspath.shouldResolveConsoleSystemResource = false
|
||||
|
||||
assertNull(javaClass.getResource("/$miraiConsoleClassPath"))
|
||||
assertNull(javaClass.classLoader.getResource(miraiConsoleClassPath))
|
||||
assertEquals(0, javaClass.classLoader.getSizeOfResources(miraiConsoleClassPath))
|
||||
|
||||
assertNull(javaClass.getResource("/$miraiBotClassPath"))
|
||||
assertNull(javaClass.classLoader.getResource(miraiBotClassPath))
|
||||
|
||||
assertEquals(0, javaClass.classLoader.getSizeOfResources(allClassesPath))
|
||||
}
|
||||
}
|
@ -2023,6 +2023,8 @@ public abstract interface class net/mamoe/mirai/console/plugin/jvm/JvmPluginClas
|
||||
public abstract fun getPluginFile ()Ljava/io/File;
|
||||
public abstract fun getPluginIndependentLibrariesClassLoader ()Ljava/lang/ClassLoader;
|
||||
public abstract fun getPluginSharedLibrariesClassLoader ()Ljava/lang/ClassLoader;
|
||||
public abstract fun getShouldResolveConsoleSystemResource ()Z
|
||||
public abstract fun setShouldResolveConsoleSystemResource (Z)V
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/console/plugin/jvm/JvmPluginDescription : net/mamoe/mirai/console/plugin/description/PluginDescription {
|
||||
|
@ -22,6 +22,7 @@ import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
/*
|
||||
Class resolving:
|
||||
@ -146,6 +147,29 @@ internal class DynLibClassLoader : DynamicClasspathClassLoader {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun tryFastOrStrictResolveResources(name: String): Enumeration<URL> {
|
||||
if (name.startsWith("java/")) return JavaSystemPlatformClassLoader.getResources(name)
|
||||
|
||||
// All mirai-core hard-linked should use same version to avoid errors (ClassCastException).
|
||||
val fromDependencies = AllDependenciesClassesHolder.appClassLoader.getResources(name)
|
||||
|
||||
return if (
|
||||
name.startsWith("net/mamoe/mirai/")
|
||||
|| name.startsWith("kotlin/")
|
||||
|| name.startsWith("kotlinx/")
|
||||
|| name.startsWith("org/slf4j/")
|
||||
) { // Avoid plugin classing cheating
|
||||
fromDependencies
|
||||
} else {
|
||||
LinkedHashSet<URL>().apply {
|
||||
addAll(fromDependencies)
|
||||
addAll(JavaSystemPlatformClassLoader.getResources(name))
|
||||
}.let {
|
||||
Collections.enumeration(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun loadClassInThisClassLoader(name: String): Class<*>? {
|
||||
@ -458,13 +482,12 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
}
|
||||
src.add(pluginIndependentCL.getResources(name))
|
||||
|
||||
val resolved = mutableListOf<URL>()
|
||||
src.forEach { nested ->
|
||||
nested.iterator().forEach { url ->
|
||||
if (url !in resolved)
|
||||
resolved.add(url)
|
||||
}
|
||||
val resolved = LinkedHashSet<URL>()
|
||||
|
||||
if (openaccess.shouldResolveConsoleSystemResource) {
|
||||
DynLibClassLoader.tryFastOrStrictResolveResources(name).let { resolved.addAll(it) }
|
||||
}
|
||||
src.forEach { nested -> resolved.addAll(nested) }
|
||||
|
||||
return Collections.enumeration(resolved)
|
||||
}
|
||||
@ -489,6 +512,12 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
if (name.startsWith("META-INF/services/net.mamoe.mirai.console.plugin."))
|
||||
return findResource(name)
|
||||
|
||||
if (openaccess.shouldResolveConsoleSystemResource) {
|
||||
DynLibClassLoader.tryFastOrStrictResolveResources(name)
|
||||
.takeIf { it.hasMoreElements() }
|
||||
?.let { return it.nextElement() }
|
||||
}
|
||||
|
||||
findResource(name)?.let { return it }
|
||||
// parent: ctx.sharedLibrariesLoader
|
||||
sharedLibrariesLogger.getResource(name)?.let { return it }
|
||||
@ -514,6 +543,8 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
override val pluginIndependentLibrariesClassLoader: ClassLoader
|
||||
get() = pluginIndependentCL
|
||||
|
||||
override var shouldResolveConsoleSystemResource: Boolean = false
|
||||
|
||||
private val permitted by lazy {
|
||||
arrayOf(
|
||||
this@JvmPluginClassLoaderN,
|
||||
|
@ -41,6 +41,13 @@ public interface JvmPluginClasspath {
|
||||
*/
|
||||
public val pluginIndependentLibrariesClassLoader: ClassLoader
|
||||
|
||||
/**
|
||||
* [pluginClassLoader] 是否可以通过 [ClassLoader.getResource] 获取 Mirai Console (包括依赖) 的相关资源
|
||||
*
|
||||
* 默认为 `false`
|
||||
*/
|
||||
public var shouldResolveConsoleSystemResource: Boolean
|
||||
|
||||
/**
|
||||
* 将 [file] 加入 [classLoader] 的搜索路径内
|
||||
*
|
||||
|
@ -54,4 +54,18 @@ public actual fun <K : Enum<K>, V> EnumMap(clazz: KClass<K>): MutableMap<K, V> {
|
||||
@Suppress("FunctionName")
|
||||
public actual fun <E> ConcurrentSet(): MutableSet<E> {
|
||||
return CopyOnWriteArraySet()
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [MutableCollection.addAll].
|
||||
*
|
||||
* Adds all the elements of the specified enumeration to this collection.
|
||||
* @return true if any of the specified elements was added to the collection, false if the collection was not modified.
|
||||
*/
|
||||
public fun <T> MutableCollection<T>.addAll(enumeration: Enumeration<T>): Boolean {
|
||||
var addResult = false
|
||||
while (enumeration.hasMoreElements()) {
|
||||
addResult = this.add(enumeration.nextElement())
|
||||
}
|
||||
return addResult
|
||||
}
|
Loading…
Reference in New Issue
Block a user