mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-03 15:10:14 +08:00
Using PlatformClassLoader to resolve java.*
; fix #2009
This commit is contained in:
parent
edf7622b0b
commit
8250c3da65
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
* 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.
|
||||
@ -10,7 +10,12 @@
|
||||
package net.mamoe.console.integrationtest
|
||||
|
||||
import org.junit.jupiter.api.fail
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
internal fun readStringListFromEnv(key: String): MutableList<String> {
|
||||
val size = System.getenv(key)!!.toInt()
|
||||
@ -35,3 +40,51 @@ public fun File.assertNotExists() {
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region JVM Utils
|
||||
public val vmClassfileVersion: Int = runCatching {
|
||||
val obj = ClassReader("java.lang.Object")
|
||||
val classobj = ClassNode().also { obj.accept(it, ClassReader.SKIP_CODE) }
|
||||
classobj.version
|
||||
}.recoverCatching {
|
||||
val ccl = object : ClassLoader(null) {
|
||||
fun canLoad(ver: Int) : Boolean{
|
||||
val klass = ClassWriter(ClassWriter.COMPUTE_MAXS)
|
||||
val cname =
|
||||
"net/mamoe/console/integrationtest/vtest/C${ver}_${System.currentTimeMillis()}_${UUID.randomUUID()}"
|
||||
.replace('-', '_')
|
||||
|
||||
klass.visit(
|
||||
ver,
|
||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
||||
cname,
|
||||
null, "java/lang/Object", null
|
||||
)
|
||||
klass.visitMethod(Opcodes.ACC_PRIVATE, "<init>", "()V", null, null)!!.also { cinit ->
|
||||
cinit.visitVarInsn(Opcodes.ALOAD, 0)
|
||||
cinit.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
||||
cinit.visitInsn(Opcodes.RETURN)
|
||||
cinit.visitMaxs(0, 0)
|
||||
}
|
||||
val code = klass.toByteArray()
|
||||
return kotlin.runCatching {
|
||||
val k = defineClass(null, code, 0, code.size)
|
||||
Class.forName(k.name, true, this)
|
||||
}.isSuccess
|
||||
}
|
||||
}
|
||||
if (ccl.canLoad(Opcodes.V17)) return@recoverCatching Opcodes.V17
|
||||
if (ccl.canLoad(Opcodes.V16)) return@recoverCatching Opcodes.V16
|
||||
if (ccl.canLoad(Opcodes.V15)) return@recoverCatching Opcodes.V15
|
||||
if (ccl.canLoad(Opcodes.V14)) return@recoverCatching Opcodes.V14
|
||||
if (ccl.canLoad(Opcodes.V13)) return@recoverCatching Opcodes.V13
|
||||
if (ccl.canLoad(Opcodes.V12)) return@recoverCatching Opcodes.V12
|
||||
if (ccl.canLoad(Opcodes.V11)) return@recoverCatching Opcodes.V11
|
||||
if (ccl.canLoad(Opcodes.V10)) return@recoverCatching Opcodes.V10
|
||||
if (ccl.canLoad(Opcodes.V9)) return@recoverCatching Opcodes.V9
|
||||
Opcodes.V1_8
|
||||
}.getOrElse { Opcodes.V1_8 } // Fallback
|
||||
|
||||
public fun canVmLoad(opversion: Int): Boolean = opversion <= vmClassfileVersion
|
||||
|
||||
// endregion
|
||||
|
@ -9,9 +9,12 @@
|
||||
|
||||
package net.mamoe.console.integrationtest.ep.pddd
|
||||
|
||||
import net.mamoe.console.integrationtest.canVmLoad
|
||||
import net.mamoe.mirai.console.extension.PluginComponentStorage
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||
import net.mamoe.mirai.utils.info
|
||||
import org.objectweb.asm.Opcodes
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
/*
|
||||
@ -35,9 +38,16 @@ internal object P : KotlinPlugin(
|
||||
|
||||
// console-non-hard-link dependency
|
||||
// mirai-core used 1.64 current
|
||||
val bc = Class.forName("org.bouncycastle.LICENSE")
|
||||
assertEquals(
|
||||
"1.63.0",
|
||||
Class.forName("org.bouncycastle.LICENSE").`package`.implementationVersion
|
||||
bc.`package`.implementationVersion,
|
||||
message = "$bc <- ${bc.classLoader}"
|
||||
)
|
||||
// #2009
|
||||
if (canVmLoad(Opcodes.V11)) {
|
||||
logger.info { "V11" }
|
||||
Class.forName("java.net.http.HttpClient")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ internal class DynLibClassLoader(
|
||||
}
|
||||
|
||||
override fun loadClass(name: String, resolve: Boolean): Class<*> {
|
||||
if (name.startsWith("java.")) return Class.forName(name, false, null)
|
||||
if (name.startsWith("java.")) return Class.forName(name, false, JavaSystemPlatformClassLoader)
|
||||
val pt = this.parent
|
||||
val topPt: ClassLoader? = if (pt is DynLibClassLoader) {
|
||||
pt.findButNoSystem(name)?.let { return it }
|
||||
@ -303,7 +303,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
override fun loadClass(name: String, resolve: Boolean): Class<*> = loadClass(name)
|
||||
|
||||
override fun loadClass(name: String): Class<*> {
|
||||
if (name.startsWith("java.")) return Class.forName(name, false, null)
|
||||
if (name.startsWith("java.")) return Class.forName(name, false, JavaSystemPlatformClassLoader)
|
||||
if (name.startsWith("io.netty") || name in AllDependenciesClassesHolder.allclasses) {
|
||||
return AllDependenciesClassesHolder.appClassLoader.loadClass(name)
|
||||
}
|
||||
@ -411,6 +411,16 @@ internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
|
||||
}
|
||||
|
||||
private val JavaSystemPlatformClassLoader: ClassLoader by lazy {
|
||||
kotlin.runCatching {
|
||||
ClassLoader::class.java.methods.asSequence().filter {
|
||||
it.name == "getPlatformClassLoader"
|
||||
}.filter {
|
||||
java.lang.reflect.Modifier.isStatic(it.modifiers)
|
||||
}.firstOrNull()?.invoke(null) as ClassLoader?
|
||||
}.getOrNull() ?: ClassLoader.getSystemClassLoader().parent
|
||||
}
|
||||
|
||||
private fun String.pkgName(): String = substringBeforeLast('.', "")
|
||||
internal fun Artifact.depId(): String = "$groupId:$artifactId"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user