Created
August 17, 2023 15:14
-
-
Save yongjhih/51e0c1bb60d6e57300a16dd88880c451 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| fun <T : Any> Class<T>.getDeclaredFieldOrNull(name: String): Field? = | |
| tryOrNull { getDeclaredField(name) } | |
| @Suppress("SpreadOperator") | |
| fun <T : Any> Class<T>.getDeclaredMethodOrNull(name: String, vararg parameterTypes: Class<*>): Method? = | |
| tryOrNull { getDeclaredMethod(name, *parameterTypes) } | |
| @Suppress("SpreadOperator") | |
| fun <T : Any> Class<T>.getDeclaredConstructorOrNull(vararg parameterTypes: Class<*>): Constructor<T>? = | |
| tryOrNull { getDeclaredConstructor(*parameterTypes) } | |
| fun <V: Any?> Any.setField(name: String, value: V): Field? = tryOrNull { | |
| [email protected](name, value) | |
| } | |
| fun <V: Any?> Any.setFieldOrThrow(name: String, value: V): Field = javaClass.getDeclaredField(name).apply { | |
| isAccessible = true | |
| set(this@setFieldOrThrow, value) | |
| } | |
| class TypedValues { | |
| val list: MutableList<Pair<Class<*>, Any?>> = mutableListOf() | |
| @JvmName("addPair") | |
| fun <T: Any> add(pair: Pair<Class<T>, T?>) = list.add(pair) | |
| @JvmName("addNullablePrimitive") | |
| inline fun <reified T: Any> add(value: T?) = add((T::class.javaPrimitiveType ?: T::class.java) to value) | |
| } | |
| /** | |
| * Usage: | |
| * | |
| * ``` | |
| * val result = obj.invokeMethod<String>("methodName") { | |
| * ``` | |
| */ | |
| @Suppress("SpreadOperator") | |
| fun <V: Any?> Any.invokeMethodOrThrow(name: String, onParameters: TypedValues.() -> Unit = {}): V = run { | |
| val (types, values) = TypedValues().apply(onParameters).list.unzip() | |
| javaClass.getDeclaredMethod(name, *(types.toTypedArray())).run { | |
| @Suppress("UNCHECKED_CAST") | |
| invoke(this@invokeMethodOrThrow, *(values.toTypedArray())) as V | |
| } | |
| } | |
| fun <V: Any?> Any.invokeMethod(name: String, onParameters: TypedValues.() -> Unit = {}): V? = tryOrNull { | |
| [email protected](name, onParameters) | |
| } | |
| @Suppress("SpreadOperator") | |
| inline fun <reified T: Any> Class<T>.newInstanceOrThrow(onParameters: TypedValues.() -> Unit = {}): T = run { | |
| val (types, values) = TypedValues().apply(onParameters).list.unzip() | |
| getDeclaredConstructor(*(types.toTypedArray())).run { newInstance(*(values.toTypedArray())) } | |
| } | |
| inline fun <reified T: Any> Class<T>.newInstance(onParameters: TypedValues.() -> Unit = {}) = tryOrNull { | |
| [email protected](onParameters) | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Test fun setField() { val range = IntProgression.fromClosedRange(0, 10, 1) range.setField("first", 2) range.first shouldBe 2 } @Test fun invokeMethod() { IntProgression.fromClosedRange(0, 10, 1).invokeMethod<Boolean>("isEmpty") shouldBe false IntProgression.fromClosedRange(0, -1, 1).invokeMethod<Boolean>("isEmpty") shouldBe true } @Test fun newInstance() { IntRange::class.java.newInstance { add(Int::class.java to 0) add(Int::class.java to 1) }?.isEmpty() shouldBe false IntRange::class.java.newInstance { add(Int::class.java to 0) add(Int::class.java to -1) }?.isEmpty() shouldBe true IntRange::class.java.newInstance { add(Int::class.java to 0) add(Int::class.java to -1) add(Int::class.java to 2) } shouldBe null IntRange::class.java.newInstance { add(0) add(-1) }?.isEmpty() shouldBe true IntRange::class.java.newInstance { add<String>(null) add<String>(null) } shouldBe null IntRange::class.java.newInstance { add<Int>(null) add<Int>(null) } shouldBe null }