From b5150955a0a7155a48cdf5fbe73bf5d2ac6eab98 Mon Sep 17 00:00:00 2001 From: tursom Date: Sat, 8 Jan 2022 21:22:42 +0800 Subject: [PATCH] update --- settings.gradle.kts | 1 + .../main/kotlin/cn/tursom/mail/EmailData.kt | 8 +- .../kotlin/cn/tursom/mail/GroupEmailData.kt | 5 +- .../src/main/kotlin/cn/tursom/mail/Mail.kt | 7 + .../cn/tursom/mail/MultipleEmailData.kt | 8 +- ts-core/ts-reflect/build.gradle.kts | 22 + .../cn/tursom/reflect/GetDeclaredMethod.kt | 98 ++++ .../reflect/GetDeclaredMethodByClass.kt | 76 +++ .../tursom/reflect/GetStaticDeclaredMethod.kt | 198 ++++++++ .../cn/tursom/reflect/InstantAllocator.kt | 58 +++ .../main/kotlin/cn/tursom/reflect/Members.kt | 272 +++++++++++ .../kotlin/cn/tursom/reflect/MethodFilter.kt | 36 ++ .../cn/tursom/reflect/MethodInspector.kt | 456 ++++++++++++++++++ .../cn/tursom/reflect/NoargMethodFilter.kt | 31 ++ .../main/kotlin/cn/tursom/reflect/Parser.kt | 210 ++++++++ .../tursom/reflect/ReturnTypeMethodFilter.kt | 22 + .../main/kotlin/cn/tursom/reflect/utils.kt | 47 ++ .../database/ktorm/AssignmentsBuilderExt.kt | 19 + .../tursom/database/ktorm/QueryRowSetExt.kt | 7 + 19 files changed, 1571 insertions(+), 10 deletions(-) create mode 100644 ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/Mail.kt create mode 100644 ts-core/ts-reflect/build.gradle.kts create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethod.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethodByClass.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetStaticDeclaredMethod.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/InstantAllocator.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Members.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodFilter.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodInspector.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/NoargMethodFilter.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Parser.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/ReturnTypeMethodFilter.kt create mode 100644 ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/utils.kt create mode 100644 ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/AssignmentsBuilderExt.kt create mode 100644 ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/QueryRowSetExt.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index cb4b711..e17461b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,6 +20,7 @@ include("ts-core:ts-json") include("ts-core:ts-xml") include("ts-core:ts-async-http") include("ts-core:ts-proxy") +include("ts-core:ts-reflect") include("ts-socket") include("ts-web") include("ts-web:ts-web-netty") diff --git a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/EmailData.kt b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/EmailData.kt index a9bebde..e27397b 100644 --- a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/EmailData.kt +++ b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/EmailData.kt @@ -30,12 +30,12 @@ import javax.mail.internet.MimeMultipart data class EmailData( var host: String?, var port: Int?, var name: String?, var password: String?, var from: String?, var to: String?, var subject: String?, var html: String? = null, var text: String? = null, - var image: Collection? = null, var attachment: Collection? = null -) { + var image: Collection? = null, var attachment: Collection? = null, +) : Mail { /** * 发送邮件 */ - fun send(transportListener: TransportListener? = null) { + override fun send(transportListener: TransportListener?) { if (host == null || port == null || name == null || password == null || from == null || to == null || subject == null) return val props = Properties() // props["mail.debug"] = "true" // 开启debug调试 @@ -69,7 +69,7 @@ data class EmailData( html: String?, text: String?, image: Collection?, - attachment: Collection? + attachment: Collection?, ): MimeMessage { //邮件内容部分 val msg = MimeMessage(session) diff --git a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/GroupEmailData.kt b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/GroupEmailData.kt index 8f3e275..9eab39a 100644 --- a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/GroupEmailData.kt +++ b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/GroupEmailData.kt @@ -15,9 +15,8 @@ data class GroupEmailData( var host: String?, var port: Int?, var name: String?, var password: String?, var from: String?, var to: Collection?, var subject: String?, var html: String? = null, var text: String? = null, var image: Collection? = null, var attachment: Collection? = null, -) { - fun send() = send(null) - fun send(transportListener: TransportListener?) { +) : Mail { + override fun send(transportListener: TransportListener?) { if (host == null || port == null || name == null || password == null || from == null || to?.isEmpty() != false || subject == null) return val props = Properties() // props["mail.debug"] = "true" // 开启debug调试 diff --git a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/Mail.kt b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/Mail.kt new file mode 100644 index 0000000..c8e2024 --- /dev/null +++ b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/Mail.kt @@ -0,0 +1,7 @@ +package cn.tursom.mail + +import javax.mail.event.TransportListener + +interface Mail { + fun send(transportListener: TransportListener? = null) +} \ No newline at end of file diff --git a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/MultipleEmailData.kt b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/MultipleEmailData.kt index 462ac25..86b2081 100644 --- a/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/MultipleEmailData.kt +++ b/ts-core/ts-mail/src/main/kotlin/cn/tursom/mail/MultipleEmailData.kt @@ -4,6 +4,7 @@ import com.sun.mail.util.MailSSLSocketFactory import java.util.* import javax.mail.Address import javax.mail.Session +import javax.mail.event.TransportListener import javax.mail.internet.InternetAddress data class MultipleEmailData( @@ -12,9 +13,9 @@ data class MultipleEmailData( var name: String?, var password: String?, var from: String?, - var to: Collection? -) { - fun send() { + var to: Collection?, +) : Mail { + override fun send(transportListener: TransportListener?) { val from = from ?: return val props = Properties() // props["mail.debug"] = "true" // 开启debug调试 @@ -32,6 +33,7 @@ data class MultipleEmailData( //发送邮件 val transport = session.transport transport.connect(host, name, password) + transportListener?.apply { transport.addTransportListener(this) } to?.forEach { (to, subject, html, text, image, attachment) -> //邮件内容部分 val msg = EmailData.getMsg(session, from, subject, html, text, image, attachment) diff --git a/ts-core/ts-reflect/build.gradle.kts b/ts-core/ts-reflect/build.gradle.kts new file mode 100644 index 0000000..35250fc --- /dev/null +++ b/ts-core/ts-reflect/build.gradle.kts @@ -0,0 +1,22 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") + `maven-publish` + id("ts-gradle") + kotlin("plugin.allopen") version "1.5.21" +} + +dependencies { + api(project(":ts-core")) + api(project(":ts-core:ts-log")) + testApi(group = "junit", name = "junit", version = "4.13.2") +} + +artifacts { + archives(tasks["kotlinSourcesJar"]) +} + +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += "-Xjvm-default=all" +} diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethod.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethod.kt new file mode 100644 index 0000000..bb92a14 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethod.kt @@ -0,0 +1,98 @@ +@file:Suppress("unused") + +package cn.tursom.reflect + +import cn.tursom.core.uncheckedCast +import java.lang.reflect.Method + +inline fun Class<*>.getDeclaredMethod( + returnType: Class<*>, + getMethod: Class<*>.() -> Method?, + staticReturn: (method: Method) -> R, +): R? { + val method = this.getDeclaredMethod(returnType, false, getMethod) + if (method != null) return staticReturn(method) + return null +} + +inline fun Any.getMethod( + name: String, + clazz: Class<*> = javaClass, + returnType: Class = R::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name) + }, +): (() -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { method(this).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod(name, returnType, getMethod) + +inline fun Any.getMethod1( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + clazz: Class<*> = javaClass, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type) + }, +): ((T1) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { method(this, it).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod1(name, returnType, arg1Type, getMethod) + +inline fun Any.getMethod2( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + clazz: Class<*> = javaClass, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type) + }, +): ((T1, T2) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2 -> method(this, v1, v2).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod2(name, returnType, arg1Type, arg2Type, getMethod) + +inline fun Any.getMethod3( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + clazz: Class<*> = javaClass, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type) + }, +): ((T1, T2, T3) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3 -> method(this, v1, v2, v3).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod3(name, returnType, arg1Type, arg2Type, arg3Type, getMethod) + +inline fun Any.getMethod4( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + clazz: Class<*> = javaClass, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) + }, +): ((T1, T2, T3, T4) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3, v4 -> method(this, v1, v2, v3, v4).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod4(name, returnType, arg1Type, arg2Type, arg3Type, arg4Type, getMethod) + +inline fun Any.getMethod5( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + arg5Type: Class = T5::class.java, + clazz: Class<*> = javaClass, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type) + }, +): ((T1, T2, T3, T4, T5) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3, v4, v5 -> method(this, v1, v2, v3, v4, v5).uncheckedCast() } +} ?: clazz.getStaticDeclaredMethod5(name, returnType, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, getMethod) + diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethodByClass.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethodByClass.kt new file mode 100644 index 0000000..5990947 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetDeclaredMethodByClass.kt @@ -0,0 +1,76 @@ +@file:Suppress("unused") + +package cn.tursom.reflect + +import cn.tursom.core.uncheckedCast +import java.lang.reflect.Method + +inline fun Class<*>.getMethod( + name: String, + returnType: Class = R::class.java, + getMethod: Class<*>.() -> Method? = { getMethodFully(name) }, +): (This.() -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { method(this).uncheckedCast() } +} + +inline fun Class<*>.getMethod1( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type) }, +): (This.(T1) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { method(this, it).uncheckedCast() } +} + +inline fun Class<*>.getMethod2( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type, arg2Type) }, +): (This.(T1, T2) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2 -> method(this, v1, v2).uncheckedCast() } +} + +inline fun Class<*>.getMethod3( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type) + }, +): (This.(T1, T2, T3) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3 -> method(this, v1, v2, v3).uncheckedCast() } +} + +inline fun Class<*>.getMethod4( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) + }, +): (This.(T1, T2, T3, T4) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3, v4 -> method(this, v1, v2, v3, v4).uncheckedCast() } +} + +inline fun Class<*>.getMethod5( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + arg5Type: Class = T5::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) + }, +): (This.(T1, T2, T3, T4, T5) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> + { v1, v2, v3, v4, v5 -> method(this, v1, v2, v3, v4, v5).uncheckedCast() } +} + diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetStaticDeclaredMethod.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetStaticDeclaredMethod.kt new file mode 100644 index 0000000..c02a5fb --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/GetStaticDeclaredMethod.kt @@ -0,0 +1,198 @@ +@file:Suppress("unused") + +package cn.tursom.reflect + +import cn.tursom.core.allMethodsSequence +import cn.tursom.core.companionObjectInstanceOrNull +import cn.tursom.core.uncheckedCast +import java.lang.reflect.Method + +inline fun getType() = T::class.java + +fun main() { + println(Int::class.java canCast getType()) + println(Int::class.java canCast getType()) +} + +infix fun Class<*>.canCast(target: Class<*>): Boolean { + return (target == Any::class.java || this == target) || ( + (this == Void.TYPE || this == Void::class.java) && + (target == Unit::class.java || target == Void.TYPE || target == Void::class.java) + ) || ( + (this == Byte::class.java || this == getType()) && + (target == Byte::class.java || target == getType()) + ) || ( + (this == Short::class.java || this == getType()) && + (target == Short::class.java || target == getType()) + ) || ( + (this == Int::class.java || this == getType()) && + (target == Int::class.java || target == getType()) + ) || ( + (this == Long::class.java || this == getType()) && + (target == Long::class.java || target == getType()) + ) || ( + (this == Float::class.java || this == getType()) && + (target == Float::class.java || target == getType()) + ) || ( + (this == Double::class.java || this == getType()) && + (target == Double::class.java || target == getType()) + ) || ( + (this == Boolean::class.java || this == getType()) && + (target == Boolean::class.java || target == getType()) + ) || ( + (this == Char::class.java || this == getType()) && + (target == Char::class.java || target == getType()) + ) || target.isAssignableFrom(this) +} + +private fun Method.match(name: String, vararg type: Class<*>): Boolean { + if (this.name != name) return false + if (this.parameterTypes.size != type.size) return false + this.parameterTypes.forEachIndexed { index, clazz -> + if (!(type[index] canCast clazz)) return false + } + return true +} + +fun Class<*>.getFirstMatchMethod( + name: String, + vararg type: Class<*>, +): Method? { + allMethodsSequence.forEach { method -> + if (method.match(name, *type)) { + return method + } + } + return null +} + +fun Class<*>.getMethodFully( + name: String, + vararg type: Class<*>, +): Method? { + val scanMethod = scanMethod(name, *type) + return (scanMethod.firstOrNull { method -> + method.parameterTypes.forEachIndexed { index, clazz -> + if (type[index] != clazz) return@firstOrNull false + } + true + } ?: scanMethod.firstOrNull()) +} + +fun Class<*>.scanMethod( + name: String, + vararg type: Class<*>, +): List { + @OptIn(ExperimentalStdlibApi::class) + return buildList { + allMethodsSequence.forEach { method -> + if (method.match(name, *type)) add(method) + } + } +} + +inline fun Class<*>.getDeclaredMethod( + returnType: Class<*>, + isStatic: Boolean = true, + getMethod: Class<*>.() -> Method?, +) = try { + val method = getMethod() + method?.isAccessible = true + if (method != null && method.isStatic() == isStatic && method.returnType canCast returnType) method + else null +} catch (e: Exception) { + null +} + +inline fun Class<*>.getStaticDeclaredMethod( + returnType: Class<*>, + getMethod: Class<*>.() -> Method?, + staticReturn: (method: Method, companionObjectInstance: Any?) -> R, +): R? { + val method = getDeclaredMethod(returnType, true, getMethod) + if (method != null) return staticReturn(method, null) + + val companionObjectInstance = kotlin.companionObjectInstanceOrNull ?: return null + val companionObjectClazz = companionObjectInstance.javaClass + val companionMethod = companionObjectClazz.getDeclaredMethod(returnType, false, getMethod) + if (companionMethod != null) return staticReturn(companionMethod, companionObjectInstance) + + return null +} + +inline fun Class<*>.getStaticDeclaredMethod( + name: String, + returnType: Class = R::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name) + }, +): (() -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { method(companion).uncheckedCast() } } + +inline fun Class<*>.getStaticDeclaredMethod1( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type) + }, +): ((T1) -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { v1 -> method(companion, v1).uncheckedCast() } } + +inline fun Class<*>.getStaticDeclaredMethod2( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type) + }, +): ((T1, T2) -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { v1, v2 -> method(companion, v1, v2).uncheckedCast() } } + +inline fun Class<*>.getStaticDeclaredMethod3( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type) + }, +): ((T1, T2, T3) -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { v1, v2, v3 -> method(companion, v1, v2, v3).uncheckedCast() } } + +inline fun Class<*>.getStaticDeclaredMethod4( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) + }, +): ((T1, T2, T3, T4) -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { v1, v2, v3, v4 -> method(companion, v1, v2, v3, v4).uncheckedCast() } } + +inline fun Class<*>.getStaticDeclaredMethod5( + name: String, + returnType: Class = R::class.java, + arg1Type: Class = T1::class.java, + arg2Type: Class = T2::class.java, + arg3Type: Class = T3::class.java, + arg4Type: Class = T4::class.java, + arg5Type: Class = T5::class.java, + getMethod: Class<*>.() -> Method? = { + getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type) + }, +): ((T1, T2, T3, T4, T5) -> R)? = getStaticDeclaredMethod( + returnType, getMethod +) { method, companion -> { v1, v2, v3, v4, v5 -> method(companion, v1, v2, v3, v4, v5).uncheckedCast() } } + + diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/InstantAllocator.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/InstantAllocator.kt new file mode 100644 index 0000000..39540e0 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/InstantAllocator.kt @@ -0,0 +1,58 @@ +package cn.tursom.reflect + +import cn.tursom.core.UncheckedCast +import cn.tursom.core.Unsafe +import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast +import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.KClass + +object InstantAllocator { + enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE } + + private val allocateFunctionMap = ConcurrentHashMap, AllocateFunction>() + + @Throws(NoSuchMethodException::class) + operator fun invoke(clazz: Class, unsafe: Boolean = true): T = get(clazz, unsafe) + + @Throws(NoSuchMethodException::class) + inline operator fun invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe) + + @Throws(NoSuchMethodException::class) + operator fun get(clazz: KClass, unsafe: Boolean = true): T = get(clazz.java, unsafe) + + @Throws(NoSuchMethodException::class) + operator fun get(clazz: Class, unsafe: Boolean = true): T { + return when (allocateFunctionMap[clazz]) { + null -> try { + val newInstance = clazz.newInstance() + allocateFunctionMap[clazz] = AllocateFunction.INSTANCE + newInstance + } catch (e: Exception) { + val kClass = clazz.kotlin + val objectInstance = kClass.objectInstance + if (objectInstance != null) { + allocateFunctionMap[clazz] = AllocateFunction.KOBJECT + objectInstance + } else if (unsafe) try { + allocateFunctionMap[clazz] = AllocateFunction.UNSAFE + @OptIn(UncheckedCast::class) + Unsafe.unsafe.allocateInstance(clazz).cast() + } catch (e: Exception) { + allocateFunctionMap[clazz] = AllocateFunction.NONE + throw NoSuchMethodException("${clazz.name}:()") + } else { + throw NoSuchMethodException("${clazz.name}:()") + } + } + AllocateFunction.INSTANCE -> clazz.newInstance() + AllocateFunction.UNSAFE -> if (unsafe) { + Unsafe.unsafe.allocateInstance(clazz).uncheckedCast() + } else { + throw NoSuchMethodException("${clazz.name}:()") + } + AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!! + AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:()") + } + } +} diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Members.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Members.kt new file mode 100644 index 0000000..6d10245 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Members.kt @@ -0,0 +1,272 @@ +@file:Suppress("unused") + +package cn.tursom.reflect + +import java.lang.reflect.Field +import java.lang.reflect.Member +import java.lang.reflect.Modifier + + +private val fieldModifiersField: Field? = try { + Field::class.java.getDeclaredField("modifiers").apply { + isAccessible = true + } +} catch (e: Throwable) { + null +} + +var fieldModifiers: (Field, Int) -> Unit = { field, modifer -> + fieldModifiersField!!.set(field, modifer) +} + +var Field.public: Boolean + get() = Modifier.isPublic(this.modifiers) + set(value) { + val modifier = Modifier.PUBLIC + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.private: Boolean + get() = Modifier.isPrivate(this.modifiers) + set(value) { + val modifier = Modifier.PRIVATE + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.protected: Boolean + get() = Modifier.isProtected(this.modifiers) + set(value) { + val modifier = Modifier.PROTECTED + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.static: Boolean + get() = Modifier.isStatic(this.modifiers) + set(value) { + val modifier = Modifier.STATIC + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.final: Boolean + get() = Modifier.isFinal(this.modifiers) + set(value) { + val modifier = Modifier.FINAL + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.synchronized: Boolean + get() = Modifier.isSynchronized(this.modifiers) + set(value) { + val modifier = Modifier.SYNCHRONIZED + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.volatile: Boolean + get() = Modifier.isVolatile(this.modifiers) + set(value) { + val modifier = Modifier.VOLATILE + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.transient: Boolean + get() = Modifier.isTransient(this.modifiers) + set(value) { + val modifier = Modifier.TRANSIENT + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.native: Boolean + get() = Modifier.isNative(this.modifiers) + set(value) { + val modifier = Modifier.NATIVE + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.`interface`: Boolean + get() = Modifier.isInterface(this.modifiers) + set(value) { + val modifier = Modifier.INTERFACE + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.abstract: Boolean + get() = Modifier.isAbstract(this.modifiers) + set(value) { + val modifier = Modifier.ABSTRACT + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +var Field.strict: Boolean + get() = Modifier.isStrict(this.modifiers) + set(value) { + val modifier = Modifier.STRICT + fieldModifiers( + this, + if (value) { + modifiers or modifier + } else { + modifiers and modifier.inv() + } + ) + } + +fun Member.isPublic(): Boolean { + return Modifier.isPublic(this.modifiers) +} + +fun Member.isPrivate(): Boolean { + return Modifier.isPrivate(this.modifiers) +} + +fun Member.isProtected(): Boolean { + return Modifier.isProtected(this.modifiers) +} + +fun Member.isStatic(): Boolean { + return Modifier.isStatic(this.modifiers) +} + +fun Member.isFinal(): Boolean { + return Modifier.isFinal(this.modifiers) +} + +fun Member.isSynchronized(): Boolean { + return Modifier.isSynchronized(this.modifiers) +} + +fun Member.isVolatile(): Boolean { + return Modifier.isVolatile(this.modifiers) +} + +fun Member.isTransient(): Boolean { + return Modifier.isTransient(this.modifiers) +} + +fun Member.isNative(): Boolean { + return Modifier.isNative(this.modifiers) +} + +fun Member.isInterface(): Boolean { + return Modifier.isInterface(this.modifiers) +} + +fun Member.isAbstract(): Boolean { + return Modifier.isAbstract(this.modifiers) +} + +fun Member.isStrict(): Boolean { + return Modifier.isStrict(this.modifiers) +} + +val Class<*>.isPublic: Boolean + get() = Modifier.isPublic(this.modifiers) + +val Class<*>.isPrivate: Boolean + get() = Modifier.isPrivate(this.modifiers) + +val Class<*>.isProtected: Boolean + get() = Modifier.isProtected(this.modifiers) + +val Class<*>.isStatic: Boolean + get() = Modifier.isStatic(this.modifiers) + +val Class<*>.isFinal: Boolean + get() = Modifier.isFinal(this.modifiers) + +val Class<*>.isSynchronized: Boolean + get() = Modifier.isSynchronized(this.modifiers) + +val Class<*>.isVolatile: Boolean + get() = Modifier.isVolatile(this.modifiers) + +val Class<*>.isTransient: Boolean + get() = Modifier.isTransient(this.modifiers) + +val Class<*>.isNative: Boolean + get() = Modifier.isNative(this.modifiers) + +//val Class<*>.isInterface: Boolean +// get() = Modifier.isInterface(this.modifiers) + +val Class<*>.isAbstract + get() = Modifier.isAbstract(this.modifiers) + +val Class<*>.isStrict + get() = Modifier.isStrict(this.modifiers) diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodFilter.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodFilter.kt new file mode 100644 index 0000000..05a6e90 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodFilter.kt @@ -0,0 +1,36 @@ +package cn.tursom.reflect + +import java.lang.reflect.Method + +interface MethodFilter { + fun filterMethod(clazz: Class<*>): Sequence + + companion object +} + + +class Arg1MethodFilter( + val prevFilter: ReturnTypeMethodFilter, +) : MethodFilter { + override fun filterMethod(clazz: Class<*>): Sequence { + return prevFilter.filterMethod(clazz).filter { method -> + method.parameterCount == 1 + } + } + + fun filter(clazz: Class): Sequence R> { + return filterMethod(clazz).map { + { + it.invoke(this) as R + } + } + } + + fun filter(obj: Any): Sequence<() -> R> { + return filterMethod(obj.javaClass).map { + { + it.invoke(obj) as R + } + } + } +} diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodInspector.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodInspector.kt new file mode 100644 index 0000000..fbac6ba --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/MethodInspector.kt @@ -0,0 +1,456 @@ +package cn.tursom.reflect + +import cn.tursom.core.UncheckedCast +import cn.tursom.core.cast +import cn.tursom.core.forAllMethods +import cn.tursom.log.impl.Slf4jImpl +import java.lang.reflect.Method +import java.lang.reflect.ParameterizedType +import kotlin.coroutines.Continuation +import kotlin.reflect.jvm.javaType +import kotlin.reflect.jvm.kotlinFunction + +@Suppress("unused", "MemberVisibilityCanBePrivate") +object MethodInspector : Slf4jImpl() { + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + argumentType: Array>, + self: Any? = null, + handler: (Method, (Array) -> R) -> Unit, + ) { + clazz.forAllMethods { method -> + val parameterTypes = method.parameterTypes + val methodReturnType = if ( + method.returnType == Void.TYPE || + method.returnType == Void::class.java + ) Unit::class.java else method.returnType + + val argumentTypeIterator = argumentType.iterator() + if (parameterTypes.size == argumentType.size && + parameterTypes.all { + argumentTypeIterator.next().isAssignableFrom(it) + } && + returnType.isAssignableFrom(methodReturnType) + ) { + method.isAccessible = true + @OptIn(UncheckedCast::class) + handler(method) { method.invoke(self, *it).cast() } + } + } + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + argumentType: Array>, + self: Any? = null, + handler: (Method, suspend (Array) -> R) -> Unit, + ) { + clazz.forAllMethods { method -> + val parameterTypes = method.parameterTypes + val kotlinFunction = method.kotlinFunction ?: return@forAllMethods + var methodReturnType = kotlinFunction.returnType.javaType + while (methodReturnType is ParameterizedType) { + methodReturnType = methodReturnType.rawType + } + + if (methodReturnType !is Class<*>) { + warn("method return type {}({}) is not Class", methodReturnType, methodReturnType.javaClass) + return@forAllMethods + } + + val argumentTypeIterator = argumentType.iterator() + if (parameterTypes.size - 1 == argumentType.size && + parameterTypes.dropLast(1).all { + argumentTypeIterator.next().isAssignableFrom(it) + } && + Continuation::class.java.isAssignableFrom(parameterTypes.last()) && + returnType.isAssignableFrom(methodReturnType) + ) { + method.isAccessible = true + @OptIn(UncheckedCast::class) + handler(method, { it: Array, cont: Continuation<*> -> method.invoke(self, *it, cont) }.cast()) + } + } + } + + fun forEachMethod(clazz: Class<*>, self: Any? = null, handler: (Method, () -> Unit) -> Unit) { + forEachMethod(clazz, Unit::class.java, self, handler) + } + + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + self: Any? = null, + handler: (Method, () -> R) -> Unit, + ) { + clazz.javaClass.forAllMethods { method -> + val parameterTypes = method.parameterTypes + val methodReturnType = if ( + method.returnType == Void.TYPE || + method.returnType == Void::class.java + ) Unit::class.java else method.returnType + if (parameterTypes.isEmpty() && returnType.isAssignableFrom(methodReturnType)) { + method.isAccessible = true + @OptIn(UncheckedCast::class) + handler(method) { method.invoke(self).cast() } + } + } + } + + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + argumentType: Class, + self: Any? = null, + handler: (Method, (T) -> R) -> Unit, + ) { + forEachMethod(clazz, returnType, arrayOf(argumentType), self) { method: Method, m: (Array) -> R -> + handler(method) { + m(arrayOf(it)) + } + } + } + + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + self: Any? = null, + handler: (Method, (T1, T2) -> R) -> Unit, + ) { + forEachMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2), + self + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2 -> + m(arrayOf(t1, t2)) + } + } + } + + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + self: Any? = null, + handler: (Method, (T1, T2, T3) -> R) -> Unit, + ) { + forEachMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3), + self + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2, t3 -> + m(arrayOf(t1, t2, t3)) + } + } + } + + fun forEachMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + argumentType4: Class, + self: Any? = null, + handler: (Method, (T1, T2, T3, T4) -> R) -> Unit, + ) { + forEachMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3, argumentType4), + self + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2, t3, t4 -> + m(arrayOf(t1, t2, t3, t4)) + } + } + } + + fun forEachSuspendMethod(clazz: Class<*>, self: Any? = null, handler: (Method, suspend () -> Unit) -> Unit) { + forEachSuspendMethod(clazz, Unit::class.java, self, handler) + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + self: Any? = null, + handler: (Method, suspend () -> R) -> Unit, + ) { + forEachSuspendMethod(clazz, returnType, arrayOf(), self) { method: Method, m: suspend (Array) -> R -> + handler(method) { + m(arrayOf()) + } + } + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + argumentType: Class, + self: Any? = null, + handler: (Method, suspend (T) -> R) -> Unit, + ) { + forEachSuspendMethod( + clazz, + returnType, + arrayOf(argumentType), + self + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { + m(arrayOf(it)) + } + } + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + self: Any? = null, + handler: (Method, suspend (T1, T2) -> R) -> Unit, + ) { + forEachSuspendMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2), + self + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2 -> + m(arrayOf(t1, t2)) + } + } + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + self: Any? = null, + handler: (Method, suspend (T1, T2, T3) -> R) -> Unit, + ) { + forEachSuspendMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3), + self + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2, t3 -> + m(arrayOf(t1, t2, t3)) + } + } + } + + fun forEachSuspendMethod( + clazz: Class<*>, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + argumentType4: Class, + self: Any? = null, + handler: (Method, suspend (T1, T2, T3, T4) -> R) -> Unit, + ) { + forEachSuspendMethod( + clazz, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3, argumentType4), + self + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2, t3, t4 -> + m(arrayOf(t1, t2, t3, t4)) + } + } + } + + + fun forEachMethod( + self: Any, + returnType: Class, + argumentType: Array>, + handler: (Method, (Array) -> R) -> Unit, + ) { + forEachMethod(self.javaClass, returnType, argumentType, self, handler) + } + + fun forEachSuspendMethod( + self: Any, + returnType: Class, + argumentType: Array>, + handler: (Method, suspend (Array) -> R) -> Unit, + ) { + forEachSuspendMethod(self.javaClass, returnType, argumentType, self, handler) + } + + fun forEachMethod(self: Any, handler: (Method, () -> Unit) -> Unit) { + forEachMethod(self, Unit::class.java, handler) + } + + fun forEachMethod(self: Any, returnType: Class, handler: (Method, () -> R) -> Unit) { + forEachMethod(self.javaClass, returnType, self, handler) + } + + fun forEachMethod( + self: Any, + returnType: Class, + argumentType: Class, + handler: (Method, (T) -> R) -> Unit, + ) { + forEachMethod(self, returnType, arrayOf(argumentType)) { method: Method, m: (Array) -> R -> + handler(method) { + m(arrayOf(it)) + } + } + } + + fun forEachMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + handler: (Method, (T1, T2) -> R) -> Unit, + ) { + forEachMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2) + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2 -> + m(arrayOf(t1, t2)) + } + } + } + + fun forEachMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + handler: (Method, (T1, T2, T3) -> R) -> Unit, + ) { + forEachMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3) + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2, t3 -> + m(arrayOf(t1, t2, t3)) + } + } + } + + fun forEachMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + argumentType4: Class, + handler: (Method, (T1, T2, T3, T4) -> R) -> Unit, + ) { + forEachMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3, argumentType4) + ) { method: Method, m: (Array) -> R -> + handler(method) { t1, t2, t3, t4 -> + m(arrayOf(t1, t2, t3, t4)) + } + } + } + + fun forEachSuspendMethod(self: Any, handler: (Method, suspend () -> Unit) -> Unit) { + forEachSuspendMethod(self, Unit::class.java, handler) + } + + fun forEachSuspendMethod(self: Any, returnType: Class, handler: (Method, suspend () -> R) -> Unit) { + forEachSuspendMethod(self, returnType, arrayOf()) { method: Method, m: suspend (Array) -> R -> + handler(method) { + m(arrayOf()) + } + } + } + + fun forEachSuspendMethod( + self: Any, + returnType: Class, + argumentType: Class, + handler: (Method, suspend (T) -> R) -> Unit, + ) { + forEachSuspendMethod(self, returnType, arrayOf(argumentType)) { method: Method, m: suspend (Array) -> R -> + handler(method) { + m(arrayOf(it)) + } + } + } + + fun forEachSuspendMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + handler: (Method, suspend (T1, T2) -> R) -> Unit, + ) { + forEachSuspendMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2) + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2 -> + m(arrayOf(t1, t2)) + } + } + } + + fun forEachSuspendMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + handler: (Method, suspend (T1, T2, T3) -> R) -> Unit, + ) { + forEachSuspendMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3) + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2, t3 -> + m(arrayOf(t1, t2, t3)) + } + } + } + + fun forEachSuspendMethod( + self: Any, + returnType: Class, + argumentType1: Class, + argumentType2: Class, + argumentType3: Class, + argumentType4: Class, + handler: (Method, suspend (T1, T2, T3, T4) -> R) -> Unit, + ) { + forEachSuspendMethod( + self, + returnType, + arrayOf(argumentType1, argumentType2, argumentType3, argumentType4) + ) { method: Method, m: suspend (Array) -> R -> + handler(method) { t1, t2, t3, t4 -> + m(arrayOf(t1, t2, t3, t4)) + } + } + } +} \ No newline at end of file diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/NoargMethodFilter.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/NoargMethodFilter.kt new file mode 100644 index 0000000..db90eb2 --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/NoargMethodFilter.kt @@ -0,0 +1,31 @@ +package cn.tursom.reflect + +import java.lang.reflect.Method + +class NoargMethodFilter( + val prevFilter: ReturnTypeMethodFilter, +) : MethodFilter { + override fun filterMethod(clazz: Class<*>): Sequence { + return prevFilter.filterMethod(clazz).filter { method -> + method.parameterCount == 0 + } + } + + fun filter(clazz: Class): Sequence R> { + return filterMethod(clazz).map { + { + it.invoke(this) as R + } + } + } + + fun filter(obj: Any): Sequence<() -> R> { + return filterMethod(obj.javaClass).map { + { + it.invoke(obj) as R + } + } + } +} + +fun ReturnTypeMethodFilter.noarg() = NoargMethodFilter(this) diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Parser.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Parser.kt new file mode 100644 index 0000000..baa8cef --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/Parser.kt @@ -0,0 +1,210 @@ +package cn.tursom.reflect + +import cn.tursom.core.* +import java.lang.reflect.Array +import java.lang.reflect.Field +import java.lang.reflect.Modifier +import java.lang.reflect.ParameterizedType +import java.util.* + +object Parser { + private val simpleDateFormat = ThreadLocalSimpleDateFormat() + private val Field.actualTypeArguments get() = (genericType as ParameterizedType).actualTypeArguments[0] as Class<*> + + fun parse(yaml: Any, clazz: Class): T? { + @Suppress("UNCHECKED_CAST") + @OptIn(UncheckedCast::class) + return when { + clazz.isInstance(yaml) -> yaml.cast() + clazz.isInheritanceFrom(Enum::class.java) -> (clazz as Class>).valueOf(yaml.toString()) as? T? + clazz.isInheritanceFrom(Map::class.java) -> { + val map = try { + clazz.newInstance() + } catch (e: Exception) { + try { + Unsafe.unsafe.allocateInstance(clazz) + } catch (e: Exception) { + HashMap() + } + }.cast>() + if (yaml !is Map<*, *>) return null + yaml.forEach { (any, u) -> + map[any] = u + } + map.cast() + } + yaml is List<*> && clazz.isArray -> parseArray(yaml, clazz) as T + else -> when (clazz) { + Any::class.java -> yaml + Int::class.java -> yaml.toInt() + Long::class.java -> yaml.toLong() + Float::class.java -> yaml.toFloat() + Double::class.java -> yaml.toDouble() + Boolean::class.java -> yaml.toBoolean() + + getClazz() -> yaml.toInt() + getClazz() -> yaml.toLong() + getClazz() -> yaml.toFloat() + getClazz() -> yaml.toDouble() + getClazz() -> yaml.toBoolean() + Date::class.java -> yaml.toDate() + String::class.java -> yaml.toString() + + else -> { + if (yaml !is Map<*, *>) return null + val instance = try { + clazz.newInstance() + } catch (e: Exception) { + Unsafe.unsafe.allocateInstance(clazz) + } + val fields = clazz.declaredFields + fields.forEach { + if ((it.modifiers and (Modifier.STATIC or Modifier.TRANSIENT)) != 0) return@forEach + try { + val parse = parseField(yaml[it.name] ?: return@forEach, it) ?: return@forEach + it.isAccessible = true + it.set(instance, parse) + } catch (e: Exception) { + } + } + instance + } + } as T + } + } + + private fun parseField(yaml: Any, field: Field): Any? { + val clazz = field.type + @Suppress("UNCHECKED_CAST") + return when (yaml) { + is List<*> -> { + when { + clazz.isAssignableFrom(List::class.java) -> { + val type = field.actualTypeArguments + if (type == Any::class.java) { + yaml + } else { + val list = try { + clazz.newInstance() as MutableList + } catch (e: Exception) { + try { + Unsafe.unsafe.allocateInstance(clazz) as MutableList + } catch (e: Exception) { + ArrayList() + } + } + yaml.forEach { + list.add(parse(it ?: return@forEach, type) ?: return@forEach) + } + list + } + } + clazz.isAssignableFrom(Set::class.java) -> { + val type = field.actualTypeArguments + if (type == Any::class.java) { + yaml + } else { + val set: MutableSet = try { + clazz.newInstance() as MutableSet + } catch (e: Exception) { + try { + Unsafe.unsafe.allocateInstance(clazz) as MutableSet + } catch (e: Exception) { + HashSet() + } + } + yaml.forEach { + set.add(parse(it ?: return@forEach, type) ?: return@forEach) + } + set + } + } + clazz.isArray -> parseArray(yaml, clazz) + else -> null + } + } + else -> parse(yaml, clazz) + } + } + + private fun parseArray(yaml: List, clazz: Class): kotlin.Array? { + val componentType = clazz.componentType + val list = ArrayList() + yaml.forEach { + list.add(parse(it ?: return@forEach, componentType) ?: return@forEach) + } + val instance = Array.newInstance(componentType, list.size) + list.forEachIndexed { index, any -> Array.set(instance, index, any) } + @Suppress("UNCHECKED_CAST") + return instance as kotlin.Array? + } + + private fun Any.toInt() = when (this) { + is Number -> toInt() + is Boolean -> if (this) 1 else 0 + is String -> toIntOrNull() + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> toString().toIntOrNull() + } + + private fun Any.toLong() = when (this) { + is Number -> toLong() + is Boolean -> if (this) 1L else 0L + is String -> toLongOrNull() + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> toString().toLongOrNull() + } + + private fun Any.toFloat() = when (this) { + is Number -> toFloat() + is Boolean -> if (this) 1.0f else 0.0f + is String -> toFloatOrNull() + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> toString().toFloatOrNull() + } + + private fun Any.toDouble() = when (this) { + is Number -> toDouble() + is Boolean -> if (this) 1.0 else 0.0 + is String -> toDoubleOrNull() + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> toString().toDoubleOrNull() + } + + private fun Any.toBoolean(): Boolean? = when (this) { + is Boolean -> this + is Number -> 0 != toInt() + is String -> equals("t", true) || equals("true", true) + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> toString().toBoolean() + } + + private fun Any.toDate(): Date? = when (this) { + is Number -> Date(toLong()) + is Boolean -> null + is String -> when (val time = toLongOrNull()) { + null -> simpleDateFormat.get().parse(this) + else -> Date(time) + } + is Iterable<*> -> null + is Iterator<*> -> null + is Map<*, *> -> null + else -> { + val str = toString() + when (val time = str.toLongOrNull()) { + null -> simpleDateFormat.get().parse(str) + else -> Date(time) + } + } + } +} \ No newline at end of file diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/ReturnTypeMethodFilter.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/ReturnTypeMethodFilter.kt new file mode 100644 index 0000000..36515ef --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/ReturnTypeMethodFilter.kt @@ -0,0 +1,22 @@ +package cn.tursom.reflect + +import cn.tursom.core.allMethodsSequence +import java.lang.reflect.Method + +class ReturnTypeMethodFilter( + val returnType: Class, +) : MethodFilter { + override fun filterMethod(clazz: Class<*>): Sequence { + return clazz.allMethodsSequence.filter { method -> + val methodReturnType = if ( + method.returnType == Void.TYPE || + method.returnType == Void::class.java + ) Unit::class.java else method.returnType + returnType.isAssignableFrom(methodReturnType) + } + } + + companion object +} + +inline fun MethodFilter.Companion.returnType() = ReturnTypeMethodFilter(R::class.java) diff --git a/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/utils.kt b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/utils.kt new file mode 100644 index 0000000..208714f --- /dev/null +++ b/ts-core/ts-reflect/src/main/kotlin/cn/tursom/reflect/utils.kt @@ -0,0 +1,47 @@ +package cn.tursom.reflect + +import cn.tursom.core.Unsafe.get +import cn.tursom.core.companionObjectInstanceOrNull +import cn.tursom.core.uncheckedCast +import java.lang.reflect.Field +import java.lang.reflect.Method + +inline fun Class<*>.getAnnotation(): T? = getAnnotation(T::class.java) +inline fun Field.getAnnotation(): T? = getAnnotation(T::class.java) +inline fun Method.getAnnotation(): T? = getAnnotation(T::class.java) + +operator fun Class<*>.contains(obj: Any): Boolean = isInstance(obj) + +fun Class<*>.getStaticField(name: String): T? { + val staticField = getDeclaredField(name) + if (staticField.isStatic()) { + staticField.isAccessible = true + return staticField.get(null).uncheckedCast() + } + + val companionObjectInstance = kotlin.companionObjectInstanceOrNull + if (companionObjectInstance != null) { + return companionObjectInstance[name]?.uncheckedCast() + } + + return null +} + +inline fun getStaticField(name: String): T? { + return C::class.java.getStaticField(name) +} + +@Suppress("UNCHECKED_CAST") +fun > Class.valueOf(value: String): T? { + var valueOf: Method? = null + return try { + valueOf = getDeclaredMethod("valueOf", String::class.java) + valueOf.invoke(null, value) as T + } catch (e: Exception) { + try { + valueOf?.invoke(null, value.toUpperCase()) as? T? + } catch (e: Exception) { + null + } + } +} diff --git a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/AssignmentsBuilderExt.kt b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/AssignmentsBuilderExt.kt new file mode 100644 index 0000000..79e1184 --- /dev/null +++ b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/AssignmentsBuilderExt.kt @@ -0,0 +1,19 @@ +package cn.tursom.database.ktorm + +import org.ktorm.dsl.AssignmentsBuilder +import org.ktorm.schema.ColumnDeclaring +import kotlin.reflect.KProperty1 + +inline fun AssignmentsBuilder.set( + column: KProperty1, + value: C?, +) { + set(AutoTable[T::class.java][column], value) +} + +inline fun AssignmentsBuilder.set( + column: KProperty1, + expr: ColumnDeclaring, +) { + set(AutoTable[T::class.java][column], expr) +} diff --git a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/QueryRowSetExt.kt b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/QueryRowSetExt.kt new file mode 100644 index 0000000..1870f13 --- /dev/null +++ b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/QueryRowSetExt.kt @@ -0,0 +1,7 @@ +package cn.tursom.database.ktorm + +import org.ktorm.dsl.QueryRowSet +import kotlin.reflect.KProperty1 + +inline operator fun QueryRowSet.get(column: KProperty1) = + get(AutoTable[T::class.java][column])