Skip to content

Instantly share code, notes, and snippets.

@mike-neck
Created July 16, 2016 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mike-neck/6b2414b59489bd63f9926388772fcd2e to your computer and use it in GitHub Desktop.
Save mike-neck/6b2414b59489bd63f9926388772fcd2e to your computer and use it in GitHub Desktop.
KotlinのKClassプロパティを調べた
@file:JvmName("Comp")
package com.sample.reflection
import java.io.Closeable
fun foo(bar: String): String = bar.toUpperCase()
val baz: Int = foo("baz").length
class Qux {
val prop: String = "ooo"
fun function(t: Int, msg: String): List<String> =
if (t < 0) emptyList() else (1..t).map { "$msg$it" }
fun <R: Closeable> R.tryAndClose(action: (R) -> Unit) {
try {
action(this)
} finally {
this.close()
}
}
val Quux.id: String
get() = this.name
fun Qux.foop(): String = this.prop.plus(this.toString())
companion object {
@JvmStatic fun add(q: Qux, qx: Quux): Int =
q.prop.length + qx.name.length
fun garply(q: Quux): Garply = object: Garply {
override val waldo: String = q.name
}
fun boolean(b: Bool): String = when (b) {
Bool.OK -> "true"
Bool.NG -> "false"
}
}
}
class Quux(val name: String) {
constructor(q: Qux): this(q.prop)
}
interface Garply {
val waldo: String
val dp: Int
get() = 1
fun lorem(q: Qux): Quux = Quux(q.prop)
companion object: Garply {
override val waldo: String = "waldo"
}
}
object Vip
annotation class Ano(val name: String)
enum class Bool(val asBoolean: Boolean) {
OK(true ){ override val int: Int = 1 },
NG(false){ override val int: Int = 0 };
abstract val int: Int
fun Vip.size(): Int = 10
val Ano.size: Int
get() = this.name.length
companion object {
fun list(): List<Bool> = values().toList()
}
}
enum class Ord {
LT,EQ,GT
}
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestName
import java.util.*
import kotlin.reflect.*
import kotlin.reflect.jvm.jvmName
class ReflectionTest {
@get:Rule
val current: TestName = TestName()
val TestName.name: String
get() = this.methodName
@Test fun `members`() {
runCollection({ it.members }) {it.name}
}
@Test fun `functions`() {
runCollection({ it.functions }) {it.name}
}
@Test fun `constructors`() {
runCollection({ it.constructors }) {it.name}
}
@Test fun `qualified name`() {
run({ it.qualifiedName })
}
@Test fun `simple name`() {
run({ it.simpleName })
}
@Test fun `jvmName`() {
run({ it.jvmName })
}
@Test fun `annotations`() {
runCollection({ it.annotations })
}
@Test fun `nested classes`() {
runCollection({ it.nestedClasses }) { it.simpleName ?: "-nn-" }
}
@Test fun `object instance`() {
run({ it.objectInstance })
}
@Test fun `companion object`() {
run({ it.companionObject }) { if (it == null) "(null)" else it.simpleName ?: "-nn-" }
}
@Test fun `companion object instance`() {
run({ it.companionObjectInstance }) { if (it == null) "(null)" else "$it" }
}
@Test fun `declared member properties`() {
runCollection({ it.declaredMemberProperties }) { it.name }
}
@Test fun `declared member extension properties`() {
runCollection({ it.declaredMemberExtensionProperties }) { it.name }
}
@Test fun `declared functions`() {
runCollection({ it.declaredFunctions }) { it.name }
}
@Test fun `declared member functions`() {
runCollection({ it.declaredMemberFunctions }) { it.name }
}
@Test fun `declared member extension functions`() {
runCollection({ it.declaredMemberExtensionFunctions }) { it.name }
}
@Test fun `default type`() {
run({ it.defaultType }) { "$it${if (it.isMarkedNullable) "?" else ""}" }
}
@Test fun `member properties`() {
runCollection({ it.memberProperties }) { it.name }
}
@Test fun `member functions`() {
runCollection({ it.memberFunctions }) { it.name }
}
@Test fun `member extension properties`() {
runCollection({ it.memberExtensionProperties }) { it.name }
}
@Test fun `member extension functions`() {
runCollection({ it.memberExtensionFunctions }) { it.name }
}
@Test fun `primary constructor`() {
run({ it.primaryConstructor }) { if (it == null) "(null)" else it.name }
}
@Test fun `static functions`() {
runCollection({ it.staticFunctions }) { it.name }
}
@Test fun `static properties`() {
runCollection({ it.staticProperties }) { it.name }
}
fun <T> run(test: (KClass<Any>) -> T, convert: (T) -> String = {"$it"}) {
println(current.name)
classes.map {
@Suppress("UNCHECKED_CAST")
check(it.value as KClass<Any>, it.key, test, convert)
}.map { it.runCheck() }.map { it.show() }.forEach { println(it) }
}
fun <T> runCollection(test: (KClass<Any>) -> Collection<T>, convert: (T) -> String = {"$it"}) {
println(current.name)
classes.map {
@Suppress("UNCHECKED_CAST")
checkCollection(it.value as KClass<Any>, it.key, test, convert)
}.map { it.runCheck() }.map { it.show() }.forEach { println(it) }
}
companion object {
val pkg: String = "com.sample.reflection"
val classes: Map<String, KClass<out Any>> = mapOf(
"Kt class" to Class.forName("$pkg.Comp").kotlin,
"Class(no constructor)" to Qux::class,
"Class(explicit constructor)" to Quux::class,
"Companion object" to Qux.Companion::class,
"Anonymous class" to Class.forName("$pkg.Qux${'$'}Companion${'$'}garply${'$'}1").kotlin,
"WhenMappings" to Class.forName("$pkg.Qux${'$'}Companion${'$'}WhenMappings").kotlin,
"Interface" to Garply::class,
"DefaultImpls" to Class.forName("$pkg.Garply${'$'}DefaultImpls").kotlin,
"Object" to Vip::class,
"Annotation" to Ano::class,
"Enum(no impl in entries)" to Ord::class,
"Enum(impl in entries)" to Bool::class,
"Enum entries" to Class.forName("$pkg.Bool${'$'}OK").kotlin
)
fun <T> checkCollection(type: KClass<Any>, subject: String, test: (KClass<Any>) -> Collection<T>, convert: (T) -> String = {"$it"}): Check {
val test: (KClass<Any>) -> Either<String, String> = {
try {
val collection = test(it)
val result = collection.map(convert).joinToString(",", "[", "]")
Either.Right(result)
} catch (e: UnsupportedOperationException) {
Either.Left(e.javaClass.simpleName)
} catch (e: KotlinReflectionInternalError) {
Either.Left(e.javaClass.simpleName)
}
}
return Check(type, subject, test)
}
fun <T,R> T.take(f: (T) -> R): R = f(this)
fun <T> check(type: KClass<Any>, subject: String, test: (KClass<Any>) -> T, convert: (T) -> String = {"$it"}): Check {
val test: (KClass<Any>) -> Either<String, String> = {
try {
val result = test(it).take(convert)
Either.Right(result)
} catch (e: UnsupportedOperationException) {
Either.Left(e.javaClass.simpleName)
} catch (e: KotlinReflectionInternalError) {
Either.Left(e.javaClass.simpleName)
}
}
return Check(type, subject, test)
}
}
}
class Check(val type: KClass<Any>, val subject: String, val test: (KClass<Any>) -> Either<String, String>) {
fun runCheck(): CheckResult {
val result = test(type)
return CheckResult(subject, result)
}
}
class CheckResult(val subject: String, val result: Either<String, String>) {
fun showResult(): String = when (result) {
is Either.Left -> "--${result.left}--"
is Either.Right -> "${result.right}"
}
fun show(): String = String.format("%-28s%s", subject, showResult())
}
sealed class Either<out L,out R> {
abstract val left: L
abstract val right: R
class Left<out L, out R>(override val left: L): Either<L,R>() {
override val right: R
get() = throw NoSuchElementException("This is left.")
}
class Right<out L, out R>(override val right: R): Either<L,R>() {
override val left: L
get() = throw NoSuchElementException("This is right.")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment