Reflection: add KClass.createInstance
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
// WITH_REFLECT
|
||||||
|
|
||||||
|
import kotlin.reflect.createInstance
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
// Good classes
|
||||||
|
|
||||||
|
class Simple
|
||||||
|
class PrimaryWithDefaults(val d1: String = "d1", val d2: Int = 2)
|
||||||
|
class Secondary(val s: String) {
|
||||||
|
constructor() : this("s")
|
||||||
|
}
|
||||||
|
class SecondaryWithDefaults(val s: String) {
|
||||||
|
constructor(x: Int = 0) : this(x.toString())
|
||||||
|
}
|
||||||
|
class SecondaryWithDefaultsNoPrimary {
|
||||||
|
constructor(x: Int) {}
|
||||||
|
constructor(s: String = "") {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad classes
|
||||||
|
|
||||||
|
class NoNoArgConstructor(val s: String) {
|
||||||
|
constructor(x: Int) : this(x.toString())
|
||||||
|
}
|
||||||
|
class NoArgAndDefault() {
|
||||||
|
constructor(x: Int = 0) : this()
|
||||||
|
}
|
||||||
|
class DefaultPrimaryAndDefaultSecondary(val s: String = "") {
|
||||||
|
constructor(x: Int = 0) : this(x.toString())
|
||||||
|
}
|
||||||
|
class SeveralDefaultSecondaries {
|
||||||
|
constructor(x: Int = 0) {}
|
||||||
|
constructor(s: String = "") {}
|
||||||
|
constructor(d: Double = 3.14) {}
|
||||||
|
}
|
||||||
|
class PrivateConstructor private constructor()
|
||||||
|
object Object
|
||||||
|
|
||||||
|
// -----------
|
||||||
|
|
||||||
|
inline fun <reified T : Any> test() {
|
||||||
|
val instance = T::class.createInstance()
|
||||||
|
assertTrue(instance is T)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> testFail() {
|
||||||
|
try {
|
||||||
|
T::class.createInstance()
|
||||||
|
fail("createInstance should have failed on ${T::class}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
test<Any>()
|
||||||
|
test<Simple>()
|
||||||
|
test<PrimaryWithDefaults>()
|
||||||
|
test<Secondary>()
|
||||||
|
test<SecondaryWithDefaults>()
|
||||||
|
test<SecondaryWithDefaultsNoPrimary>()
|
||||||
|
|
||||||
|
testFail<NoNoArgConstructor>()
|
||||||
|
testFail<NoArgAndDefault>()
|
||||||
|
testFail<DefaultPrimaryAndDefaultSecondary>()
|
||||||
|
testFail<SeveralDefaultSecondaries>()
|
||||||
|
testFail<PrivateConstructor>()
|
||||||
|
testFail<Object>()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -11892,6 +11892,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createInstance.kt")
|
||||||
|
public void testCreateInstance() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/createInstance.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("declaredMembers.kt")
|
@TestMetadata("declaredMembers.kt")
|
||||||
public void testDeclaredMembers() throws Exception {
|
public void testDeclaredMembers() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/declaredMembers.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/classes/declaredMembers.kt");
|
||||||
|
|||||||
@@ -272,3 +272,16 @@ fun <T : Any> KClass<T>.cast(value: Any?): T {
|
|||||||
fun <T : Any> KClass<T>.safeCast(value: Any?): T? {
|
fun <T : Any> KClass<T>.safeCast(value: Any?): T? {
|
||||||
return if (isInstance(value)) value as T else null
|
return if (isInstance(value)) value as T else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which are optional
|
||||||
|
* (see [KParameter.isOptional]). If there are no or many such constructors, an exception is thrown.
|
||||||
|
*/
|
||||||
|
fun <T : Any> KClass<T>.createInstance(): T {
|
||||||
|
// TODO: throw a meaningful exception
|
||||||
|
val noArgsConstructor = constructors.singleOrNull { it.parameters.all(KParameter::isOptional) }
|
||||||
|
?: throw IllegalArgumentException("Class should have a single no-arg constructor: $this")
|
||||||
|
|
||||||
|
return noArgsConstructor.callBy(emptyMap())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user