Use Class.forName instead of ClassLoader.loadClass in reflection
This fixes an issue in constructing annotation instances with array
class elements. For some reason, behavior of `ClassLoader.loadClass`
differs from `Class.forName` in handling arrays, namely:
* `loadClass("[Ltest.Foo;")` returns null
* `Class.forName("[Ltest.Foo;")` returns class for array of test.Foo
Overall, there doesn't seem to be any way to load an array class with
`CLassLoader.loadClass`.
We pass initialize=false to forName because this is the behavior of
ClassLoader.loadClass: it doesn't perform class initialization (e.g.
<clinit> is not executed).
#KT-31318 Fixed
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class MyAnn(val cls: KClass<*>)
|
||||
|
||||
val s: @MyAnn(Array<String>::class) String = ""
|
||||
|
||||
fun box(): String {
|
||||
val ann = ::s.returnType.annotations[0] as MyAnn
|
||||
return if (ann.cls == Array<String>::class) "OK" else "Fail: ${ann.cls}"
|
||||
}
|
||||
+4
-4
@@ -58,7 +58,7 @@ fun f(): @Anno(
|
||||
AnnotationTarget.EXPRESSION,
|
||||
Nested("1"),
|
||||
["lmao"],
|
||||
[Double::class, Unit::class, LongArray::class],
|
||||
[Double::class, Unit::class, LongArray::class, Array<String>::class],
|
||||
[AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD],
|
||||
[Nested("2"), Nested("3")]
|
||||
) Unit {}
|
||||
@@ -67,9 +67,9 @@ fun box(): String {
|
||||
assertEquals(
|
||||
"[@Anno(b=1, c=x, d=3.14, f=-2.72, i=42424242, j=239239239239239, s=42, z=true, " +
|
||||
"ba=[-1], ca=[y], da=[-3.14159], fa=[2.7218], ia=[424242], ja=[239239239239], sa=[-43], za=[false, true], " +
|
||||
"str=lol, k=class java.lang.Number, k2=class [I, e=EXPRESSION, a=@Nested(value=1), " +
|
||||
"stra=[lmao], ka=[class java.lang.Double, class kotlin.Unit, class [J], ea=[TYPEALIAS, FIELD], " +
|
||||
"aa=[@Nested(value=2), @Nested(value=3)])]",
|
||||
"str=lol, k=class java.lang.Number, k2=class [I, e=EXPRESSION, a=@Nested(value=1), stra=[lmao], " +
|
||||
"ka=[class java.lang.Double, class kotlin.Unit, class [J, class [Ljava.lang.String;], " +
|
||||
"ea=[TYPEALIAS, FIELD], aa=[@Nested(value=2), @Nested(value=3)])]",
|
||||
::f.returnType.annotations.toString()
|
||||
)
|
||||
|
||||
|
||||
+5
@@ -20083,6 +20083,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/annotations/onTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayKClass.kt")
|
||||
public void testArrayKClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||
public void testClassLiteralWithExpectedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
||||
|
||||
+5
@@ -20083,6 +20083,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/annotations/onTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayKClass.kt")
|
||||
public void testArrayKClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||
public void testClassLiteralWithExpectedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
||||
|
||||
+5
@@ -18973,6 +18973,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/annotations/onTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayKClass.kt")
|
||||
public void testArrayKClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||
public void testClassLiteralWithExpectedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ class ReflectJavaClassFinder(private val classLoader: ClassLoader) : JavaClassFi
|
||||
|
||||
fun ClassLoader.tryLoadClass(fqName: String) =
|
||||
try {
|
||||
loadClass(fqName)
|
||||
Class.forName(fqName, false, this)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
null
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ private fun loadClass(classLoader: ClassLoader, packageName: String, className:
|
||||
}
|
||||
|
||||
var fqName = "$packageName.${className.replace('.', '$')}"
|
||||
repeat(arrayDimensions) {
|
||||
fqName = "[$fqName"
|
||||
if (arrayDimensions > 0) {
|
||||
fqName = "[".repeat(arrayDimensions) + "L$fqName;"
|
||||
}
|
||||
|
||||
return classLoader.tryLoadClass(fqName)
|
||||
|
||||
Reference in New Issue
Block a user