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,
|
AnnotationTarget.EXPRESSION,
|
||||||
Nested("1"),
|
Nested("1"),
|
||||||
["lmao"],
|
["lmao"],
|
||||||
[Double::class, Unit::class, LongArray::class],
|
[Double::class, Unit::class, LongArray::class, Array<String>::class],
|
||||||
[AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD],
|
[AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD],
|
||||||
[Nested("2"), Nested("3")]
|
[Nested("2"), Nested("3")]
|
||||||
) Unit {}
|
) Unit {}
|
||||||
@@ -67,9 +67,9 @@ fun box(): String {
|
|||||||
assertEquals(
|
assertEquals(
|
||||||
"[@Anno(b=1, c=x, d=3.14, f=-2.72, i=42424242, j=239239239239239, s=42, z=true, " +
|
"[@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], " +
|
"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), " +
|
"str=lol, k=class java.lang.Number, k2=class [I, e=EXPRESSION, a=@Nested(value=1), stra=[lmao], " +
|
||||||
"stra=[lmao], ka=[class java.lang.Double, class kotlin.Unit, class [J], ea=[TYPEALIAS, FIELD], " +
|
"ka=[class java.lang.Double, class kotlin.Unit, class [J, class [Ljava.lang.String;], " +
|
||||||
"aa=[@Nested(value=2), @Nested(value=3)])]",
|
"ea=[TYPEALIAS, FIELD], aa=[@Nested(value=2), @Nested(value=3)])]",
|
||||||
::f.returnType.annotations.toString()
|
::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);
|
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")
|
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||||
public void testClassLiteralWithExpectedType() throws Exception {
|
public void testClassLiteralWithExpectedType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
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);
|
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")
|
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||||
public void testClassLiteralWithExpectedType() throws Exception {
|
public void testClassLiteralWithExpectedType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
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);
|
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")
|
@TestMetadata("classLiteralWithExpectedType.kt")
|
||||||
public void testClassLiteralWithExpectedType() throws Exception {
|
public void testClassLiteralWithExpectedType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt");
|
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) =
|
fun ClassLoader.tryLoadClass(fqName: String) =
|
||||||
try {
|
try {
|
||||||
loadClass(fqName)
|
Class.forName(fqName, false, this)
|
||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ private fun loadClass(classLoader: ClassLoader, packageName: String, className:
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fqName = "$packageName.${className.replace('.', '$')}"
|
var fqName = "$packageName.${className.replace('.', '$')}"
|
||||||
repeat(arrayDimensions) {
|
if (arrayDimensions > 0) {
|
||||||
fqName = "[$fqName"
|
fqName = "[".repeat(arrayDimensions) + "L$fqName;"
|
||||||
}
|
}
|
||||||
|
|
||||||
return classLoader.tryLoadClass(fqName)
|
return classLoader.tryLoadClass(fqName)
|
||||||
|
|||||||
Reference in New Issue
Block a user