This commit is contained in:
tursom 2022-04-08 00:44:52 +08:00
parent bf2b15aee8
commit ebd7f40380
34 changed files with 1300 additions and 778 deletions

View File

@ -20,7 +20,9 @@ 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-proxy-jdk")
include("ts-core:ts-reflect")
include("ts-core:ts-reflectasm")
include("ts-socket")
include("ts-web")
include("ts-web:ts-web-netty")

View File

@ -0,0 +1,29 @@
package cn.tursom.core.sequence
class CacheSequence<T>(
private val sequence: Sequence<T>,
) : Sequence<T> {
private var list: MutableList<T>? = null
override fun iterator(): Iterator<T> = list?.iterator() ?: CacheSequenceIterator(sequence.iterator(), ArrayList())
inner class CacheSequenceIterator(
private val iterator: Iterator<T>,
private val list: MutableList<T>,
) : Iterator<T> {
override fun hasNext(): Boolean = if (iterator.hasNext()) {
true
} else {
this@CacheSequence.list = list
false
}
override fun next(): T {
val next = iterator.next()
list.add(next)
return next
}
}
}
fun <T> Sequence<T>.cache() = CacheSequence(this)

View File

@ -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:ts-reflectasm"))
implementation("org.apache.commons", "commons-lang3", "3.8.1")
testApi(group = "junit", name = "junit", version = "4.13.2")
}
artifacts {
archives(tasks["kotlinSourcesJar"])
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
}

View File

@ -9,7 +9,7 @@ plugins {
dependencies {
api(project(":ts-core"))
implementation("cglib:cglib:3.3.0")
api("cglib", "cglib", "3.3.0")
implementation("org.apache.commons", "commons-lang3", "3.8.1")
testApi(group = "junit", name = "junit", version = "4.13.2")
}

View File

@ -1,27 +0,0 @@
package cn.tursom.proxy
class ListProxy<T : ProxyMethod> : MutableProxy<T> {
private val proxyList: MutableList<T> = ArrayList()
override fun addProxy(proxy: T): Int {
proxyList.add(proxy)
return proxyList.size - 1
}
override fun addAllProxy(proxy: Collection<T>?): Boolean {
return proxyList.addAll(proxy!!)
}
override fun removeProxy(proxy: T) {
proxyList.remove(proxy)
}
override fun removeProxy(index: Int) {
proxyList.removeAt(index)
}
override fun iterator(): MutableIterator<T> {
return proxyList.iterator()
}
}

View File

@ -0,0 +1,27 @@
package cn.tursom.proxy
class ListProxyContainer : MutableProxyContainer {
private val proxyList: MutableList<ProxyMethod> = ArrayList()
override fun addProxy(proxy: ProxyMethod): Int {
proxyList.add(proxy)
return proxyList.size - 1
}
override fun addAllProxy(proxy: Collection<ProxyMethod>?): Boolean {
return proxyList.addAll(proxy!!)
}
override fun removeProxy(proxy: ProxyMethod) {
proxyList.remove(proxy)
}
override fun removeProxy(index: Int) {
proxyList.removeAt(index)
}
override fun iterator(): MutableIterator<ProxyMethod> {
return proxyList.iterator()
}
}

View File

@ -1,8 +0,0 @@
package cn.tursom.proxy
interface MutableProxy<T : ProxyMethod> : Proxy<T> {
fun addProxy(proxy: T): Int
fun addAllProxy(proxy: Collection<T>?): Boolean
fun removeProxy(proxy: T)
fun removeProxy(index: Int)
}

View File

@ -0,0 +1,8 @@
package cn.tursom.proxy
interface MutableProxyContainer : ProxyContainer {
fun addProxy(proxy: ProxyMethod): Int
fun addAllProxy(proxy: Collection<ProxyMethod>?): Boolean
fun removeProxy(proxy: ProxyMethod)
fun removeProxy(index: Int)
}

View File

@ -1,46 +1,42 @@
package cn.tursom.proxy
import cn.tursom.core.uncheckedCast
import net.sf.cglib.proxy.Enhancer
import java.util.concurrent.ConcurrentHashMap
interface Proxy<out T : ProxyMethod> : Iterable<T> {
data class Result<out R>(
val result: R,
val success: Boolean = false,
)
object Proxy {
private val cache = ConcurrentHashMap<Class<*>, Class<*>>()
companion object {
val failed: Result<*> = Result<Any?>(null, false)
fun <R> of(): Result<R?> {
return of(null)
}
private fun <T> getTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
val enhancer = Enhancer()
enhancer.setSuperclass(clazz)
enhancer.setCallbackType(ProxyInterceptor::class.java)
enhancer.setCallbackFilter { 0 }
enhancer.createClass()
}.uncheckedCast()
/**
* 返回一个临时使用的 Result 对象
* 因为是临时对象所以不要把这个对象放到任何当前函数堆栈以外的地方
* 如果要长期储存对象请 new Result
*/
fun <R> of(result: R): Result<R> {
return Result(result, true)
}
fun <R> failed(): Result<R> {
return failed.uncheckedCast()
operator fun <T> get(clazz: Class<T>, builder: (Class<T>) -> T): Pair<T, MutableProxyContainer> {
val target = getTarget(clazz)
val container = ListProxyContainer()
synchronized(target) {
Enhancer.registerCallbacks(target, arrayOf(ProxyInterceptor(container)))
return builder(target) to container
}
}
}
inline fun <T : ProxyMethod> Proxy<T>.forEachProxy(action: (T) -> Unit) {
for (t in this) {
action(t)
}
}
inline fun <reified T> get() = get(T::class.java)
inline fun <reified T> get(
argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>,
) = get(T::class.java, argumentTypes, arguments)
inline fun <R, T : ProxyMethod> Proxy<T>.forFirstProxy(action: (T) -> Proxy.Result<R>?): Proxy.Result<R> {
for (t in this) {
val result = action(t)
if (result != null && result.success) {
return result
}
operator fun <T> get(clazz: Class<T>): Pair<T, MutableProxyContainer> = get(clazz, Class<T>::newInstance)
operator fun <T> get(
clazz: Class<T>,
argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>,
): Pair<T, MutableProxyContainer> = get(clazz) {
it.getConstructor(*argumentTypes).newInstance(*arguments)
}
return Proxy.failed()
}

View File

@ -1,115 +1,47 @@
package cn.tursom.proxy
import cn.tursom.proxy.annotation.ForEachProxy
import cn.tursom.proxy.annotation.ForFirstProxy
import net.sf.cglib.proxy.MethodProxy
import org.apache.commons.lang3.StringUtils
import java.lang.reflect.Method
import java.util.*
interface ProxyContainer<T : ProxyMethod> {
@get:Throws(Throwable::class)
val proxy: Proxy<T>
/**
* will be call when proxy method invoke.
* 在代理方法被调用时该方法会被调用
*/
@Throws(Throwable::class)
fun onProxy(method: Method, args: Array<out Any?>, proxy: MethodProxy): Proxy.Result<*>? {
var handler = ProxyContainerHandlerCache.getHandler(method)
if (handler != null) {
return handler(this, method, args, proxy)
}
for (annotation in method.annotations) when (annotation) {
is ForEachProxy -> {
handler = onForeachProxy(annotation)
break
}
is ForFirstProxy -> {
handler = onForFirstProxy(annotation)
break
}
}
if (handler == null) {
handler = ProxyContainerHandlerCache.callSuper
}
ProxyContainerHandlerCache.setHandler(method, handler)
return handler(this, method, args, proxy)
}
import cn.tursom.core.uncheckedCast
data class ProxyResult<out R>(
val result: R,
val success: Boolean = false,
) {
companion object {
private val errMsgSearchList = arrayOf("%M", "%B", "%A")
fun onForFirstProxy(forFirstProxy: ForFirstProxy) = { o: Any, m: Method, a: Array<out Any?>, p: MethodProxy ->
onForFirstProxy(o, m, a, p, forFirstProxy, when (forFirstProxy.value.size) {
0 -> emptyList()
1 -> listOf(forFirstProxy.value[0].java)
else -> forFirstProxy.value.asSequence().map { it.java }.toSet()
})
val failed: ProxyResult<*> = ProxyResult<Any?>(null, false)
fun <R> of(): ProxyResult<R?> {
return of(null)
}
private fun onForFirstProxy(
obj: Any,
method: Method,
args: Array<out Any?>,
proxy: MethodProxy?,
forFirstProxy: ForFirstProxy,
classes: Collection<Class<*>>,
): Proxy.Result<*> {
if (obj !is ProxyContainer<*>) return Proxy.failed<Any>()
val result = obj.proxy.forFirstProxy { p ->
if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(p) }) {
return@forFirstProxy p.onProxy(obj, method, args, proxy)
} else {
return@forFirstProxy Proxy.failed()
}
}
if (result.success) {
return result
}
// when request not handled
if (forFirstProxy.must) {
// generate error message
var errMsg: String = forFirstProxy.errMsg
if (errMsg.isBlank()) {
errMsg = "no proxy handled on method %M"
}
val replacementList = arrayOfNulls<String>(errMsgSearchList.size)
// todo use efficient contains
if (errMsg.contains(errMsgSearchList[0])) {
replacementList[0] = method.toString()
}
if (errMsg.contains(errMsgSearchList[1])) {
replacementList[1] = obj.toString()
}
if (errMsg.contains(errMsgSearchList[2])) {
replacementList[2] = Arrays.toString(args)
}
errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList)
throw forFirstProxy.errClass.java.getConstructor(String::class.java).newInstance(errMsg)
}
return Proxy.failed
/**
* 返回一个临时使用的 Result 对象
* 因为是临时对象所以不要把这个对象放到任何当前函数堆栈以外的地方
* 如果要长期储存对象请 new Result
*/
fun <R> of(result: R): ProxyResult<R> {
return ProxyResult(result, true)
}
private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) {
0 -> emptyList()
1 -> listOf(forEachProxy.value[0].java)
else -> forEachProxy.value.asSequence().map { it.java }.toSet()
})
private fun onForeachProxy(
classes: Collection<Class<*>>,
) = label@{ o: Any, m: Method, a: Array<out Any?>, proxy1: MethodProxy ->
if (o !is ProxyContainer<*>) return@label Proxy.failed
o.proxy.forEachProxy { p ->
if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) {
p.onProxy(o, m, a, proxy1)
}
}
Proxy.failed<Any?>()
fun <R> failed(): ProxyResult<R> {
return failed.uncheckedCast()
}
}
}
interface ProxyContainer : Iterable<ProxyMethod> {
}
inline fun ProxyContainer.forEachProxy(action: (ProxyMethod) -> Unit) {
for (t in this) {
action(t)
}
}
inline fun <R> ProxyContainer.forFirstProxy(action: (ProxyMethod) -> ProxyResult<R>?): ProxyResult<R> {
for (t in this) {
val result = action(t)
if (result != null && result.success) {
return result
}
}
return ProxyResult.failed()
}

View File

@ -5,18 +5,21 @@ import java.lang.reflect.Method
import java.util.concurrent.ConcurrentHashMap
object ProxyContainerHandlerCache {
private val handlerMap: MutableMap<Method, (Any, Method, Array<out Any?>, MethodProxy) -> Proxy.Result<Any?>> =
private val handlerMap: MutableMap<Method, (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>> =
ConcurrentHashMap()
val callSuper = { obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy ->
Proxy.of<Any?>(proxy.invokeSuper(obj, args))
val callSuper = { obj: Any, _: ProxyContainer, _: Method, args: Array<out Any?>, proxy: MethodProxy ->
ProxyResult.of<Any?>(proxy.invokeSuper(obj, args))
}
val empty = { obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy -> Proxy.failed<Any?>() }
val empty = { _: Any, _: ProxyContainer, _: Method, _: Array<out Any?>, _: MethodProxy -> ProxyResult.failed<Any?>() }
fun getHandler(method: Method): ((Any, Method, Array<out Any?>, MethodProxy) -> Proxy.Result<Any?>)? {
fun getHandler(method: Method): ((Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>)? {
return handlerMap[method]
}
fun setHandler(method: Method, onProxy: ((Any, Method, Array<out Any?>, MethodProxy) -> Proxy.Result<Any?>)?) {
fun setHandler(
method: Method,
onProxy: ((Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>)?,
) {
handlerMap[method] = onProxy ?: callSuper
}
}

View File

@ -6,7 +6,9 @@ import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.*
class ProxyInterceptor : MethodInterceptor {
class ProxyInterceptor(
private val container: ProxyContainer = ListProxyContainer(),
) : MethodInterceptor {
companion object {
private val HANDLE_DEQUE_THREAD_LOCAL = ThreadLocal<ArrayDeque<Any>>()
private val parameterTypes = arrayOf(Method::class.java, Array<Any>::class.java, MethodProxy::class.java)
@ -23,47 +25,19 @@ class ProxyInterceptor : MethodInterceptor {
return method.name == name && parameterTypes.contentEquals(getParameterTypes(method))
}
private fun isOnProxyMethod(method: Method): Boolean {
fun isOnProxyMethod(method: Method): Boolean {
return equalsMethod(method, "onProxy", parameterTypes)
}
private val handleDeque: ArrayDeque<Any>
get() {
var objectArrayDeque = HANDLE_DEQUE_THREAD_LOCAL.get()
if (objectArrayDeque == null) {
objectArrayDeque = ArrayDeque()
HANDLE_DEQUE_THREAD_LOCAL.set(objectArrayDeque)
}
return objectArrayDeque
}
@Suppress("UNCHECKED_CAST")
fun <T> getHandle(): T {
return handleDeque.first as T
}
private fun push(obj: Any) {
handleDeque.push(obj)
}
private fun pop() {
handleDeque.pop()
}
}
@Throws(Throwable::class)
override fun intercept(obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy): Any? {
push(obj)
return try {
if (obj is ProxyContainer<*> && !isOnProxyMethod(method)) {
val result = obj.onProxy(method, args, proxy)
if (result != null && result.success) {
return result.result
}
if (!isOnProxyMethod(method)) {
val result = ProxyRunner.onProxy(obj, container, method, args, proxy)
if (result != null && result.success) {
return result.result
}
proxy.invokeSuper(obj, args)
} finally {
pop()
}
return proxy.invokeSuper(obj, args)
}
}

View File

@ -8,15 +8,15 @@ import java.util.concurrent.ConcurrentHashMap
interface ProxyMethod {
@Throws(Throwable::class)
fun onProxy(obj: Any?, method: Method, args: Array<out Any?>, proxy: MethodProxy?): Proxy.Result<*>? {
fun onProxy(obj: Any?, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*>? {
val selfMethod: Method
val handlerCacheMap = getHandlerCacheMap(javaClass)
val methodResult = handlerCacheMap[method]
if (methodResult != null) {
return if (methodResult.success) {
Proxy.of(methodResult.result(this, *args))
ProxyResult.of(methodResult.result(this, *args))
} else {
Proxy.failed<Any>()
ProxyResult.failed<Any>()
}
}
try {
@ -36,19 +36,19 @@ interface ProxyMethod {
}
selfMethod = javaClass.getMethod(methodName, *method.parameterTypes)
selfMethod.isAccessible = true
handlerCacheMap[method] = Proxy.Result(selfMethod, true)
handlerCacheMap[method] = ProxyResult(selfMethod, true)
} catch (e: Exception) {
handlerCacheMap[method] = Proxy.failed()
return Proxy.failed<Any>()
handlerCacheMap[method] = ProxyResult.failed()
return ProxyResult.failed<Any>()
}
return Proxy.of<Any>(selfMethod(this, *args))
return ProxyResult.of<Any>(selfMethod(this, *args))
}
companion object {
private val handlerCacheMapMap: MutableMap<Class<out ProxyMethod>, MutableMap<Method, Proxy.Result<Method>>> =
private val handlerCacheMapMap: MutableMap<Class<out ProxyMethod>, MutableMap<Method, ProxyResult<Method>>> =
HashMap()
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, Proxy.Result<Method>> {
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<Method>> {
var handlerCacheMap = handlerCacheMapMap[type]
if (handlerCacheMap == null) synchronized(handlerCacheMapMap) {
handlerCacheMap = handlerCacheMapMap[type]

View File

@ -0,0 +1,111 @@
package cn.tursom.proxy
import cn.tursom.proxy.annotation.ForEachProxy
import cn.tursom.proxy.annotation.ForFirstProxy
import net.sf.cglib.proxy.MethodProxy
import org.apache.commons.lang3.StringUtils
import java.lang.reflect.Method
import java.util.*
object ProxyRunner {
private val errMsgSearchList = arrayOf("%M", "%B", "%A")
/**
* will be call when proxy method invoke.
* 在代理方法被调用时该方法会被调用
*/
@Throws(Throwable::class)
fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> {
var handler = ProxyContainerHandlerCache.getHandler(method)
if (handler != null) {
return handler(obj, c, method, args, proxy)
}
for (annotation in method.annotations) when (annotation) {
is ForEachProxy -> {
handler = onForeachProxy(annotation)
break
}
is ForFirstProxy -> {
handler = onForFirstProxy(annotation)
break
}
}
if (handler == null) {
//handler = ProxyContainerHandlerCache.callSuper
handler = onForFirstProxy(ForFirstProxy.EMPTY)
}
ProxyContainerHandlerCache.setHandler(method, handler)
return handler(obj, c, method, args, proxy)
}
fun onForFirstProxy(forFirstProxy: ForFirstProxy) =
{ o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, p: MethodProxy ->
onForFirstProxy(o, c, m, a, p, forFirstProxy, when (forFirstProxy.value.size) {
0 -> emptyList()
1 -> listOf(forFirstProxy.value[0].java)
else -> forFirstProxy.value.asSequence().map { it.java }.toSet()
})
}
private fun onForFirstProxy(
obj: Any,
container: ProxyContainer,
method: Method,
args: Array<out Any?>,
proxy: MethodProxy,
forFirstProxy: ForFirstProxy,
classes: Collection<Class<*>>,
): ProxyResult<*> {
val result = container.forFirstProxy { p ->
if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(p) }) {
return@forFirstProxy p.onProxy(obj, method, args, proxy)
} else {
return@forFirstProxy ProxyResult.failed
}
}
if (result.success) {
return result
}
// when request not handled
if (forFirstProxy.must) {
// generate error message
var errMsg: String = forFirstProxy.errMsg
if (errMsg.isBlank()) {
errMsg = "no proxy handled on method %M"
}
val replacementList = arrayOfNulls<String>(errMsgSearchList.size)
// todo use efficient contains
if (errMsg.contains(errMsgSearchList[0])) {
replacementList[0] = method.toString()
}
if (errMsg.contains(errMsgSearchList[1])) {
replacementList[1] = obj.toString()
}
if (errMsg.contains(errMsgSearchList[2])) {
replacementList[2] = Arrays.toString(args)
}
errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList)
throw forFirstProxy.errClass.java.getConstructor(String::class.java).newInstance(errMsg)
}
return ProxyResult.failed
}
private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) {
0 -> emptyList()
1 -> listOf(forEachProxy.value[0].java)
else -> forEachProxy.value.asSequence().map { it.java }.toSet()
})
private fun onForeachProxy(
classes: Collection<Class<*>>,
) = label@{ o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, proxy1: MethodProxy ->
c.forEachProxy { p ->
if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) {
p.onProxy(o, m, a, proxy1)
}
}
ProxyResult.failed<Any?>()
}
}

View File

@ -14,4 +14,8 @@ annotation class ForFirstProxy(
val must: Boolean = false,
val errMsg: String = "",
val errClass: KClass<out RuntimeException> = RuntimeException::class,
)
) {
companion object {
val EMPTY = ForFirstProxy()
}
}

View File

@ -2,36 +2,30 @@ package cn.tursom.proxy
import cn.tursom.proxy.Example.GetA
import cn.tursom.proxy.annotation.ForEachProxy
import net.sf.cglib.proxy.Enhancer
import org.junit.Test
class Example {
open class TestClass protected constructor() : ProxyContainer<ProxyMethod> {
open class TestClass protected constructor() {
@get:ForEachProxy
open val a: Int = 0
override val proxy = ListProxy<ProxyMethod>()
}
fun interface GetA : ProxyMethod {
fun getA(): Int
}
private val enhancer = Enhancer()
init {
enhancer.setSuperclass(TestClass::class.java)
enhancer.setCallback(ProxyInterceptor())
}
@Test
fun test() {
val testClass = enhancer.create() as TestClass
testClass.proxy.addProxy(GetA {
println("on proxy method")
0
})
repeat(3) {
val (t, container) = Proxy.get<TestClass>()
container.addProxy(GetA {
println("on proxy method")
0
})
println(testClass.javaClass)
println(testClass.a)
println(t.javaClass)
println(t.a)
}
}
}

View File

@ -6,93 +6,129 @@ import cn.tursom.core.uncheckedCast
import java.lang.reflect.Method
inline fun <R> Class<*>.getDeclaredMethod(
returnType: Class<*>,
getMethod: Class<*>.() -> Method?,
staticReturn: (method: Method) -> R,
returnType: Class<*>,
getMethod: Class<*>.() -> Method?,
onGetMethod: (Method) -> Unit = {},
staticReturn: (method: Method) -> R,
): R? {
val method = this.getDeclaredMethod(returnType, false, getMethod)
if (method != null) return staticReturn(method)
return null
val method = this.getDeclaredMethod(returnType, false, getMethod)
if (method != null) {
onGetMethod(method)
return staticReturn(method)
}
return null
}
inline fun <reified R : Any> Any.getMethod(
name: String,
clazz: Class<*> = javaClass,
returnType: Class<R> = R::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name)
},
): (() -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method ->
{ method(this).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod(name, returnType, getMethod)
name: String,
clazz: Class<*> = javaClass,
returnType: Class<R> = R::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name)
},
): (() -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod(name, returnType, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1> Any.getMethod1(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = 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)
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type)
},
): ((T1) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this, it).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod1(name, returnType, arg1Type, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1, reified T2> Any.getMethod2(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = 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)
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type)
},
): ((T1, T2) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2 -> method(this, v1, v2).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod2(name, returnType, arg1Type, arg2Type, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1, reified T2, reified T3> Any.getMethod3(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = 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)
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type)
},
): ((T1, T2, T3) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3 -> method(this, v1, v2, v3).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod3(name, returnType, arg1Type, arg2Type, arg3Type, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1, reified T2, reified T3, reified T4> Any.getMethod4(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = 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)
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type)
},
): ((T1, T2, T3, T4) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4 -> method(this, v1, v2, v3, v4).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod4(name, returnType, arg1Type, arg2Type, arg3Type, arg4Type, onGetMethod, getMethod)
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Any.getMethod5(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = 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)
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
},
): ((T1, T2, T3, T4, T5) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4, v5 -> method(this, v1, v2, v3, v4, v5).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod5(
name,
returnType, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type,
onGetMethod, getMethod
)
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5, reified T6> Any.getMethod6(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java,
arg6Type: Class<T6> = T6::class.java,
clazz: Class<*> = javaClass,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, arg6Type)
},
): ((T1, T2, T3, T4, T5, T6) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4, v5, v6 -> method(this, v1, v2, v3, v4, v5, v6).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod6(
name,
returnType, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, arg6Type,
onGetMethod, getMethod
)

View File

@ -6,71 +6,96 @@ import cn.tursom.core.uncheckedCast
import java.lang.reflect.Method
inline fun <This, reified R> Class<*>.getMethod(
name: String,
returnType: Class<out R> = R::class.java,
getMethod: Class<*>.() -> Method? = { getMethodFully(name) },
): (This.() -> R)? = getDeclaredMethod(returnType, getMethod) { method ->
{ method(this).uncheckedCast() }
name: String,
returnType: Class<out R> = R::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name)
},
): (This.() -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this).uncheckedCast() }
}
inline fun <This, reified R, reified T1> Class<*>.getMethod1(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type) },
): (This.(T1) -> R)? = getDeclaredMethod(returnType, getMethod) { method ->
{ method(this, it).uncheckedCast() }
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type) },
): (This.(T1) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this, it).uncheckedCast() }
}
inline fun <This, reified R, reified T1, reified T2> Class<*>.getMethod2(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = 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() }
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type, arg2Type) },
): (This.(T1, T2) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2 -> method(this, v1, v2).uncheckedCast() }
}
inline fun <This, reified R, reified T1, reified T2, reified T3> Class<*>.getMethod3(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = 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() }
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type)
},
): (This.(T1, T2, T3) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3 -> method(this, v1, v2, v3).uncheckedCast() }
}
inline fun <This, reified R, reified T1, reified T2, reified T3, reified T4> Class<*>.getMethod4(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = 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() }
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type)
},
): (This.(T1, T2, T3, T4) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4 -> method(this, v1, v2, v3, v4).uncheckedCast() }
}
inline fun <This, reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Class<*>.getMethod5(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java,
arg5Type: Class<in T5> = 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() }
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java,
arg5Type: Class<in T5> = T5::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
},
): (This.(T1, T2, T3, T4, T5) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4, v5 -> method(this, v1, v2, v3, v4, v5).uncheckedCast() }
}
inline fun <This, reified R, reified T1, reified T2, reified T3, reified T4, reified T5, reified T6> Class<*>.getMethod6(
name: String,
returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java,
arg5Type: Class<in T5> = T5::class.java,
arg6Type: Class<in T6> = T6::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, arg6Type)
},
): (This.(T1, T2, T3, T4, T5, T6) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ v1, v2, v3, v4, v5, v6 -> method(this, v1, v2, v3, v4, v5, v6).uncheckedCast() }
}

View File

@ -4,195 +4,223 @@ package cn.tursom.reflect
import cn.tursom.core.allMethodsSequence
import cn.tursom.core.companionObjectInstanceOrNull
import cn.tursom.core.sequence.cache
import cn.tursom.core.uncheckedCast
import java.lang.reflect.Method
inline fun <reified T> getType() = T::class.java
fun main() {
println(Int::class.java canCast getType<Byte>())
println(Int::class.java canCast getType<Int>())
infix fun Class<*>.canCast(target: Class<*>): Boolean {
return (target == Any::class.java || this == target) || (
this == Void.TYPE || this == Void::class.java
//(this == Void.TYPE || this == Void::class.java) &&
// (target == Unit::class.java || target == Void.TYPE || target == Void::class.java)
) || (
(this == Byte::class.java || this == getType<Byte>()) &&
(target == Byte::class.java || target == getType<Byte>())
) || (
(this == Short::class.java || this == getType<Short>()) &&
(target == Short::class.java || target == getType<Short>())
) || (
(this == Int::class.java || this == getType<Int>()) &&
(target == Int::class.java || target == getType<Int>())
) || (
(this == Long::class.java || this == getType<Long>()) &&
(target == Long::class.java || target == getType<Long>())
) || (
(this == Float::class.java || this == getType<Float>()) &&
(target == Float::class.java || target == getType<Float>())
) || (
(this == Double::class.java || this == getType<Double>()) &&
(target == Double::class.java || target == getType<Double>())
) || (
(this == Boolean::class.java || this == getType<Boolean>()) &&
(target == Boolean::class.java || target == getType<Boolean>())
) || (
(this == Char::class.java || this == getType<Char>()) &&
(target == Char::class.java || target == getType<Char>())
) || target.isAssignableFrom(this)
}
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<Byte>()) &&
(target == Byte::class.java || target == getType<Byte>())
) || (
(this == Short::class.java || this == getType<Short>()) &&
(target == Short::class.java || target == getType<Short>())
) || (
(this == Int::class.java || this == getType<Int>()) &&
(target == Int::class.java || target == getType<Int>())
) || (
(this == Long::class.java || this == getType<Long>()) &&
(target == Long::class.java || target == getType<Long>())
) || (
(this == Float::class.java || this == getType<Float>()) &&
(target == Float::class.java || target == getType<Float>())
) || (
(this == Double::class.java || this == getType<Double>()) &&
(target == Double::class.java || target == getType<Double>())
) || (
(this == Boolean::class.java || this == getType<Boolean>()) &&
(target == Boolean::class.java || target == getType<Boolean>())
) || (
(this == Char::class.java || this == getType<Char>()) &&
(target == Char::class.java || target == getType<Char>())
) || target.isAssignableFrom(this)
infix fun Array<out Class<*>>.match(types: Array<out Class<*>>): Boolean {
forEachIndexed { index, clazz ->
if (!(types[index] canCast clazz)) return false
}
return true
}
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
if (this.name != name) return false
if (this.parameterTypes.size != type.size) return false
return this.parameterTypes match type
}
fun Class<*>.getFirstMatchMethod(
name: String,
vararg type: Class<*>,
name: String,
vararg type: Class<*>,
): Method? {
allMethodsSequence.forEach { method ->
if (method.match(name, *type)) {
return method
}
allMethodsSequence.forEach { method ->
if (method.match(name, type = type)) {
return method
}
return null
}
return null
}
fun Class<*>.getMethodFully(
name: String,
vararg type: Class<*>,
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())
val scanMethod = scanMethod(name, type = 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<Method> {
@OptIn(ExperimentalStdlibApi::class)
return buildList {
allMethodsSequence.forEach { method ->
if (method.match(name, *type)) add(method)
}
}
name: String,
vararg type: Class<*>,
): Sequence<Method> {
@OptIn(ExperimentalStdlibApi::class)
return allMethodsSequence.filter { method ->
method.match(name, type = type)
}.cache()
}
inline fun Class<*>.getDeclaredMethod(
returnType: Class<*>,
isStatic: Boolean = true,
getMethod: Class<*>.() -> Method?,
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
val method = getMethod()
method?.isAccessible = true
if (method != null && method.isStatic() == isStatic && method.returnType canCast returnType) method
else null
} catch (e: Exception) {
null
null
}
inline fun <R> Class<*>.getStaticDeclaredMethod(
returnType: Class<*>,
getMethod: Class<*>.() -> Method?,
staticReturn: (method: Method, companionObjectInstance: Any?) -> R,
returnType: Class<*>,
getMethod: Class<*>.() -> Method?,
onGetMethod: (Method) -> Unit = {},
staticReturn: (method: Method, companionObjectInstance: Any?) -> R,
): R? {
val method = getDeclaredMethod(returnType, true, getMethod)
if (method != null) return staticReturn(method, null)
val method = getDeclaredMethod(returnType, true, getMethod)
if (method != null) {
onGetMethod(method)
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)
val companionObjectInstance = kotlin.companionObjectInstanceOrNull ?: return null
val companionObjectClazz = companionObjectInstance.javaClass
val companionMethod = companionObjectClazz.getDeclaredMethod(returnType, false, getMethod)
if (companionMethod != null) {
onGetMethod(companionMethod)
return staticReturn(companionMethod, companionObjectInstance)
}
return null
return null
}
inline fun <reified R : Any> Class<*>.getStaticDeclaredMethod(
name: String,
returnType: Class<R> = R::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name)
},
name: String,
returnType: Class<R> = R::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name)
},
): (() -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { method(companion).uncheckedCast() } }
inline fun <reified R, reified T1> Class<*>.getStaticDeclaredMethod1(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type)
},
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type)
},
): ((T1) -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { v1 -> method(companion, v1).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2> Class<*>.getStaticDeclaredMethod2(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type)
},
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type)
},
): ((T1, T2) -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2 -> method(companion, v1, v2).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2, reified T3> Class<*>.getStaticDeclaredMethod3(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type)
},
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type)
},
): ((T1, T2, T3) -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3 -> method(companion, v1, v2, v3).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2, reified T3, reified T4> Class<*>.getStaticDeclaredMethod4(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type)
},
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type)
},
): ((T1, T2, T3, T4) -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3, v4 -> method(companion, v1, v2, v3, v4).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Class<*>.getStaticDeclaredMethod5(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java,
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
},
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
},
): ((T1, T2, T3, T4, T5) -> R)? = getStaticDeclaredMethod(
returnType, getMethod
returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3, v4, v5 -> method(companion, v1, v2, v3, v4, v5).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5, reified T6> Class<*>.getStaticDeclaredMethod6(
name: String,
returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java,
arg6Type: Class<T6> = T6::class.java,
onGetMethod: (Method) -> Unit = {},
getMethod: Class<*>.() -> Method? = {
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, arg6Type)
},
): ((T1, T2, T3, T4, T5, T6) -> R)? = getStaticDeclaredMethod(
returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3, v4, v5, v6 -> method(companion, v1, v2, v3, v4, v5, v6).uncheckedCast() } }

View File

@ -8,51 +8,51 @@ import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
object InstantAllocator {
enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE }
enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE }
private val allocateFunctionMap = ConcurrentHashMap<Class<*>, AllocateFunction>()
private val allocateFunctionMap = ConcurrentHashMap<Class<*>, AllocateFunction>()
@Throws(NoSuchMethodException::class)
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
@Throws(NoSuchMethodException::class)
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
@Throws(NoSuchMethodException::class)
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
@Throws(NoSuchMethodException::class)
operator fun <T> get(clazz: Class<out T>, 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<T>()
} catch (e: Exception) {
allocateFunctionMap[clazz] = AllocateFunction.NONE
throw NoSuchMethodException("${clazz.name}:<init>()")
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
}
AllocateFunction.INSTANCE -> clazz.newInstance()
AllocateFunction.UNSAFE -> if (unsafe) {
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!!
AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:<init>()")
@Throws(NoSuchMethodException::class)
operator fun <T> get(clazz: Class<out T>, 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<T>()
} catch (e: Exception) {
allocateFunctionMap[clazz] = AllocateFunction.NONE
throw NoSuchMethodException("${clazz.name}:<init>()")
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
}
AllocateFunction.INSTANCE -> clazz.newInstance()
AllocateFunction.UNSAFE -> if (unsafe) {
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
} else {
throw NoSuchMethodException("${clazz.name}:<init>()")
}
AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!!
AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:<init>()")
}
}
}

View File

@ -8,265 +8,265 @@ import java.lang.reflect.Modifier
private val fieldModifiersField: Field? = try {
Field::class.java.getDeclaredField("modifiers").apply {
isAccessible = true
}
Field::class.java.getDeclaredField("modifiers").apply {
isAccessible = true
}
} catch (e: Throwable) {
null
null
}
var fieldModifiers: (Field, Int) -> Unit = { field, modifer ->
fieldModifiersField!!.set(field, modifer)
var fieldModifiers: (Field, Int) -> Unit = { field, modifier ->
fieldModifiersField!!.set(field, modifier)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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()
}
)
}
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)
return Modifier.isPublic(this.modifiers)
}
fun Member.isPrivate(): Boolean {
return Modifier.isPrivate(this.modifiers)
return Modifier.isPrivate(this.modifiers)
}
fun Member.isProtected(): Boolean {
return Modifier.isProtected(this.modifiers)
return Modifier.isProtected(this.modifiers)
}
fun Member.isStatic(): Boolean {
return Modifier.isStatic(this.modifiers)
return Modifier.isStatic(this.modifiers)
}
fun Member.isFinal(): Boolean {
return Modifier.isFinal(this.modifiers)
return Modifier.isFinal(this.modifiers)
}
fun Member.isSynchronized(): Boolean {
return Modifier.isSynchronized(this.modifiers)
return Modifier.isSynchronized(this.modifiers)
}
fun Member.isVolatile(): Boolean {
return Modifier.isVolatile(this.modifiers)
return Modifier.isVolatile(this.modifiers)
}
fun Member.isTransient(): Boolean {
return Modifier.isTransient(this.modifiers)
return Modifier.isTransient(this.modifiers)
}
fun Member.isNative(): Boolean {
return Modifier.isNative(this.modifiers)
return Modifier.isNative(this.modifiers)
}
fun Member.isInterface(): Boolean {
return Modifier.isInterface(this.modifiers)
return Modifier.isInterface(this.modifiers)
}
fun Member.isAbstract(): Boolean {
return Modifier.isAbstract(this.modifiers)
return Modifier.isAbstract(this.modifiers)
}
fun Member.isStrict(): Boolean {
return Modifier.isStrict(this.modifiers)
return Modifier.isStrict(this.modifiers)
}
val Class<*>.isPublic: Boolean
get() = Modifier.isPublic(this.modifiers)
get() = Modifier.isPublic(this.modifiers)
val Class<*>.isPrivate: Boolean
get() = Modifier.isPrivate(this.modifiers)
get() = Modifier.isPrivate(this.modifiers)
val Class<*>.isProtected: Boolean
get() = Modifier.isProtected(this.modifiers)
get() = Modifier.isProtected(this.modifiers)
val Class<*>.isStatic: Boolean
get() = Modifier.isStatic(this.modifiers)
get() = Modifier.isStatic(this.modifiers)
val Class<*>.isFinal: Boolean
get() = Modifier.isFinal(this.modifiers)
get() = Modifier.isFinal(this.modifiers)
val Class<*>.isSynchronized: Boolean
get() = Modifier.isSynchronized(this.modifiers)
get() = Modifier.isSynchronized(this.modifiers)
val Class<*>.isVolatile: Boolean
get() = Modifier.isVolatile(this.modifiers)
get() = Modifier.isVolatile(this.modifiers)
val Class<*>.isTransient: Boolean
get() = Modifier.isTransient(this.modifiers)
get() = Modifier.isTransient(this.modifiers)
val Class<*>.isNative: Boolean
get() = Modifier.isNative(this.modifiers)
get() = Modifier.isNative(this.modifiers)
//val Class<*>.isInterface: Boolean
// get() = Modifier.isInterface(this.modifiers)
val Class<*>.isAbstract
get() = Modifier.isAbstract(this.modifiers)
get() = Modifier.isAbstract(this.modifiers)
val Class<*>.isStrict
get() = Modifier.isStrict(this.modifiers)
get() = Modifier.isStrict(this.modifiers)

View File

@ -3,34 +3,34 @@ package cn.tursom.reflect
import java.lang.reflect.Method
interface MethodFilter {
fun filterMethod(clazz: Class<*>): Sequence<Method>
fun filterMethod(clazz: Class<*>): Sequence<Method>
companion object
companion object
}
class Arg1MethodFilter<R>(
val prevFilter: ReturnTypeMethodFilter<R>,
val prevFilter: ReturnTypeMethodFilter<R>,
) : MethodFilter {
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return prevFilter.filterMethod(clazz).filter { method ->
method.parameterCount == 1
}
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return prevFilter.filterMethod(clazz).filter { method ->
method.parameterCount == 1
}
}
fun <T> filter(clazz: Class<T>): Sequence<T.() -> R> {
return filterMethod(clazz).map {
{
it.invoke(this) as R
}
}
fun <T> filter(clazz: Class<T>): Sequence<T.() -> 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 filter(obj: Any): Sequence<() -> R> {
return filterMethod(obj.javaClass).map {
{
it.invoke(obj) as R
}
}
}
}

View File

@ -3,29 +3,29 @@ package cn.tursom.reflect
import java.lang.reflect.Method
class NoargMethodFilter<R>(
val prevFilter: ReturnTypeMethodFilter<R>,
val prevFilter: ReturnTypeMethodFilter<R>,
) : MethodFilter {
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return prevFilter.filterMethod(clazz).filter { method ->
method.parameterCount == 0
}
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return prevFilter.filterMethod(clazz).filter { method ->
method.parameterCount == 0
}
}
fun <T> filter(clazz: Class<T>): Sequence<T.() -> R> {
return filterMethod(clazz).map {
{
it.invoke(this) as R
}
}
fun <T> filter(clazz: Class<T>): Sequence<T.() -> 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 filter(obj: Any): Sequence<() -> R> {
return filterMethod(obj.javaClass).map {
{
it.invoke(obj) as R
}
}
}
}
fun <R> ReturnTypeMethodFilter<R>.noarg() = NoargMethodFilter(this)

View File

@ -4,19 +4,19 @@ import cn.tursom.core.allMethodsSequence
import java.lang.reflect.Method
class ReturnTypeMethodFilter<R>(
val returnType: Class<R>,
val returnType: Class<R>,
) : MethodFilter {
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
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)
}
override fun filterMethod(clazz: Class<*>): Sequence<Method> {
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
companion object
}
inline fun <reified R> MethodFilter.Companion.returnType() = ReturnTypeMethodFilter(R::class.java)

View File

@ -13,35 +13,35 @@ inline fun <reified T : Annotation> Method.getAnnotation(): T? = getAnnotation(T
operator fun Class<*>.contains(obj: Any): Boolean = isInstance(obj)
fun <T> Class<*>.getStaticField(name: String): T? {
val staticField = getDeclaredField(name)
if (staticField.isStatic()) {
staticField.isAccessible = true
return staticField.get(null).uncheckedCast()
}
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()
}
val companionObjectInstance = kotlin.companionObjectInstanceOrNull
if (companionObjectInstance != null) {
return companionObjectInstance[name]?.uncheckedCast()
}
return null
return null
}
inline fun <reified C : Any, T> getStaticField(name: String): T? {
return C::class.java.getStaticField(name)
return C::class.java.getStaticField(name)
}
@Suppress("UNCHECKED_CAST")
fun <T : Enum<out T>> Class<out T>.valueOf(value: String): T? {
var valueOf: Method? = null
return try {
valueOf = getDeclaredMethod("valueOf", String::class.java)
valueOf.invoke(null, value) as 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) {
try {
valueOf?.invoke(null, value.toUpperCase()) as? T?
} catch (e: Exception) {
null
}
null
}
}
}

View File

@ -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:ts-reflect"))
api("com.esotericsoftware", "reflectasm", "1.11.9")
testApi(group = "junit", name = "junit", version = "4.13.2")
}
artifacts {
archives(tasks["kotlinSourcesJar"])
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
}

View File

@ -0,0 +1,15 @@
package cn.tursom.reflect.asm
import com.esotericsoftware.reflectasm.FieldAccess
import java.lang.reflect.Field
@Suppress("MemberVisibilityCanBePrivate", "unused")
class ReflectAsmField(
val fieldAccess: FieldAccess,
val index: Int,
) {
val name: String get() = fieldAccess.fieldNames[index]
val type: Class<*> get() = fieldAccess.fieldTypes[index]
val field: Field get() = fieldAccess.fields[index]
}

View File

@ -0,0 +1,30 @@
package cn.tursom.reflect.asm
import cn.tursom.core.toUpperCase
import cn.tursom.core.uncheckedCast
import com.esotericsoftware.reflectasm.MethodAccess
class ReflectAsmKtField<T, V>(
private val getterMethodAccess: MethodAccess,
private val getterIndex: Int,
private val setterMethodAccess: MethodAccess?,
private val setterIndex: Int,
) {
val settable get() = setterMethodAccess != null
operator fun get(obj: T): V = getterMethodAccess.invoke(obj, getterIndex).uncheckedCast()
operator fun set(obj: T, value: V) {
setterMethodAccess!!.invoke(obj, setterIndex, value)
}
companion object {
inline operator fun <reified T, reified R> get(fieldName: String): ReflectAsmKtField<T, R> {
val getterName = "get" + fieldName.toUpperCase(0)
val setterName = "set" + fieldName.toUpperCase(0)
val (getterMethodAccess, getterIndex) = ReflectAsmUtils.getMethod(T::class.java,
getterName, returnType = R::class.java)!!
val (setterMethodAccess, setterIndex) = ReflectAsmUtils.getMethod(T::class.java,
setterName, R::class.java) ?: (null to -1)
return ReflectAsmKtField(getterMethodAccess, getterIndex, setterMethodAccess, setterIndex)
}
}
}

View File

@ -0,0 +1,184 @@
package cn.tursom.reflect.asm
import cn.tursom.reflect.canCast
import cn.tursom.reflect.match
import com.esotericsoftware.reflectasm.FieldAccess
import com.esotericsoftware.reflectasm.MethodAccess
import java.lang.reflect.Method
import java.util.concurrent.ConcurrentHashMap
@Suppress("unused")
object ReflectAsmUtils {
private val fieldAccessMap = ConcurrentHashMap<Class<*>, List<FieldAccess>>()
private val methodAccessMap = ConcurrentHashMap<Class<*>, List<MethodAccess>>()
val Class<*>.fieldAccessList: List<FieldAccess>
get() = fieldAccessMap[this] ?: run {
var analyzeFieldAccessClass = this
val fieldAccessList = ArrayList<FieldAccess>()
while (analyzeFieldAccessClass != Any::class.java) {
try {
fieldAccessList.add(FieldAccess.get(analyzeFieldAccessClass)!!)
analyzeFieldAccessClass = analyzeFieldAccessClass.superclass
} catch (_: Exception) {
}
}
fieldAccessMap[this] = fieldAccessList
fieldAccessList
}
fun getField(clazz: Class<*>, fieldName: String, type: Class<*> = Any::class.java): Pair<FieldAccess, Int>? {
clazz.fieldAccessList.forEach { fieldAccess ->
try {
val index = fieldAccess.getIndex(fieldName)
if (fieldAccess.fieldTypes[index] canCast type) {
return fieldAccess to index
}
} catch (_: Exception) {
}
}
return null
}
inline fun <reified T, reified R> getField(fieldName: String): Pair<FieldAccess, Int>? =
getField(T::class.java, fieldName, R::class.java)
fun getReflectAsmField(clazz: Class<*>, fieldName: String, type: Class<*> = Any::class.java): ReflectAsmField? {
val (fieldAccess, index) = getField(clazz, fieldName, type) ?: return null
return ReflectAsmField(fieldAccess, index)
}
inline fun <reified T, reified R> getReflectAsmField(fieldName: String): ReflectAsmField? =
getReflectAsmField(T::class.java, fieldName, R::class.java)
val Class<*>.methodAccessList: List<MethodAccess>
get() = methodAccessMap[this] ?: run {
var analyzeFieldAccessClass = this
val fieldAccessList = ArrayList<MethodAccess>()
while (analyzeFieldAccessClass != Any::class.java) {
try {
fieldAccessList.add(MethodAccess.get(analyzeFieldAccessClass)!!)
analyzeFieldAccessClass = analyzeFieldAccessClass.superclass
} catch (_: Exception) {
}
}
methodAccessMap[this] = fieldAccessList
fieldAccessList
}
fun getMethod(
clazz: Class<*>,
methodName: String,
vararg paramTypes: Class<*>,
returnType: Class<*> = Any::class.java,
): Pair<MethodAccess, Int>? {
clazz.methodAccessList.forEach { methodAccess ->
repeat(methodAccess.methodNames.size) { i ->
if (methodAccess.methodNames[i] == methodName && methodAccess.parameterTypes[i] match paramTypes &&
methodAccess.returnTypes[i] canCast returnType
) {
return methodAccess to i
}
}
}
return null
}
fun getMethod(method: Method): Pair<MethodAccess, Int>? = getMethod(
method.declaringClass,
method.name,
paramTypes = method.parameterTypes,
returnType = method.returnType,
)
inline fun <reified T, reified R> getMethod0(methodName: String): (T.() -> R)? {
val (methodAccess, index) = getMethod(T::class.java, methodName, returnType = R::class.java)
?: return null
return {
methodAccess.invoke(this, index) as R
}
}
inline fun <reified T, reified A1, reified R> getMethod1(methodName: String): (T.(A1) -> R)? {
val (methodAccess, index) = getMethod(T::class.java, methodName, A1::class.java, returnType = R::class.java)
?: return null
return { a1 ->
methodAccess.invoke(this, index, a1) as R
}
}
inline fun <reified T, reified A1, reified A2, reified R> getMethod2(methodName: String): (T.(A1, A2) -> R)? {
val (methodAccess, index) = getMethod(T::class.java,
methodName,
A1::class.java,
A2::class.java,
returnType = R::class.java)
?: return null
return { a1, a2 ->
methodAccess.invoke(this, index, a1, a2) as R
}
}
inline fun <reified T, reified A1, reified A2, reified A3, reified R> getMethod3(methodName: String): (T.(A1, A2, A3) -> R)? {
val (methodAccess, index) = getMethod(T::class.java,
methodName,
A1::class.java,
A2::class.java,
A3::class.java,
returnType = R::class.java)
?: return null
return { a1, a2, a3 ->
methodAccess.invoke(this, index, a1, a2, a3) as R
}
}
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified R>
getMethod4(methodName: String): (T.(A1, A2, A3, A4) -> R)? {
val (methodAccess, index) = getMethod(T::class.java,
methodName,
A1::class.java,
A2::class.java,
A3::class.java,
A4::class.java,
returnType = R::class.java)
?: return null
return { a1, a2, a3, a4 ->
methodAccess.invoke(this, index, a1, a2, a3, a4) as R
}
}
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified A5, reified R>
getMethod5(methodName: String): (T.(A1, A2, A3, A4, A5) -> R)? {
val (methodAccess, index) = getMethod(T::class.java,
methodName,
A1::class.java,
A2::class.java,
A3::class.java,
A4::class.java,
A5::class.java,
returnType = R::class.java)
?: return null
return { a1, a2, a3, a4, a5 ->
methodAccess.invoke(this, index, a1, a2, a3, a4, a5) as R
}
}
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified A5, reified A6, reified R>
getMethod6(methodName: String): (T.(A1, A2, A3, A4, A5, A6) -> R)? {
val (methodAccess, index) = getMethod(T::class.java,
methodName,
A1::class.java,
A2::class.java,
A3::class.java,
A4::class.java,
A5::class.java,
A6::class.java,
returnType = R::class.java)
?: return null
return { a1, a2, a3, a4, a5, a6 ->
methodAccess.invoke(this, index, a1, a2, a3, a4, a5, a6) as R
}
}
}

View File

@ -11,10 +11,19 @@ dependencies {
implementation(project(":ts-core"))
implementation(project(":ts-core:ts-clone"))
implementation(project(":ts-core:ts-log"))
// for support ExtSqlDialect
compileOnly(project(":ts-core:ts-proxy"))
compileOnly(project(":ts-core:ts-reflectasm"))
api(group = "org.ktorm", name = "ktorm-core", version = "3.4.1")
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.9")
testApi(group = "junit", name = "junit", version = "4.13.2")
testApi(project(":ts-core:ts-proxy"))
testApi(project(":ts-core:ts-reflectasm"))
testApi(group = "org.xerial", name = "sqlite-jdbc", version = "3.36.0.3")
testApi(group = "org.ktorm", name = "ktorm-support-sqlite", version = "3.4.1")
}

View File

@ -0,0 +1,26 @@
package cn.tursom.database.ktorm.ext
import org.ktorm.expression.ScalarExpression
import org.ktorm.expression.SqlExpression
import org.ktorm.schema.SqlType
class DirectSqlExpression<T : Any>(
val sql: String,
override val sqlType: SqlType<T>,
override val isLeafNode: Boolean = false,
override val extraProperties: Map<String, Any> = emptyMap(),
) : ScalarExpression<T>() {
companion object {
val visitor = { expr: SqlExpression, builder: StringBuilder ->
if (expr is DirectSqlExpression<*>) {
builder.append(expr.sql)
true
} else {
false
}
}
infix fun <T : Any> SqlType<T>.sql(sql: String) = DirectSqlExpression(sql, this)
}
}

View File

@ -0,0 +1,28 @@
package cn.tursom.database.ktorm.ext
import cn.tursom.core.allFieldsSequence
import cn.tursom.core.reflect.InstantAllocator
import cn.tursom.proxy.Proxy
import org.ktorm.database.Database
import org.ktorm.database.SqlDialect
import org.ktorm.database.detectDialectImplementation
import org.ktorm.expression.SqlFormatter
class ExtSqlDialect(
private val sqlDialect: SqlDialect = detectDialectImplementation(),
) : SqlDialect by sqlDialect {
override fun createSqlFormatter(database: Database, beautifySql: Boolean, indentSize: Int): SqlFormatter {
val formatter = sqlDialect.createSqlFormatter(database, beautifySql, indentSize)
val (proxyFormatter, container) = Proxy[formatter.javaClass, InstantAllocator::get]
run {
val extSqlFormatter = ExtSqlFormatter(formatter)
extSqlFormatter.registerVisitor(DirectSqlExpression.visitor)
container.addProxy(extSqlFormatter)
}
formatter.javaClass.allFieldsSequence.forEach { field ->
field.isAccessible = true
field.set(proxyFormatter, field.get(formatter))
}
return proxyFormatter
}
}

View File

@ -0,0 +1,30 @@
package cn.tursom.database.ktorm.ext
import cn.tursom.proxy.ProxyMethod
import cn.tursom.reflect.asm.ReflectAsmKtField
import org.ktorm.expression.SqlExpression
import org.ktorm.expression.SqlFormatter
class ExtSqlFormatter(
private val prevFormatter: SqlFormatter,
) : ProxyMethod {
companion object {
private val builderField = ReflectAsmKtField.get<SqlFormatter, StringBuilder>("_builder")
}
private val visitorList = ArrayList<(expr: SqlExpression, builder: StringBuilder) -> Boolean>()
fun registerVisitor(visitor: (expr: SqlExpression, builder: StringBuilder) -> Boolean) {
visitorList.add(visitor)
}
fun visitUnknown(expr: SqlExpression): SqlExpression {
val builder = builderField[prevFormatter]
visitorList.forEach {
if (it(expr, builder)) {
return expr
}
}
return expr
}
}

View File

@ -0,0 +1,22 @@
package cn.tursom.database.ktorm.ext
import cn.tursom.database.ktorm.ext.DirectSqlExpression.Companion.sql
import org.junit.Test
import org.ktorm.database.Database
import org.ktorm.dsl.eq
import org.ktorm.schema.IntSqlType
import org.sqlite.SQLiteDataSource
internal class ExtSqlDialectTest {
@Test
fun createSqlFormatter() {
val database = Database.connect(SQLiteDataSource().let {
it.url = "jdbc:sqlite::memory:"
it
}, dialect = ExtSqlDialect())
val formatter = database.dialect.createSqlFormatter(database, false, 2)
formatter.visit(IntSqlType sql "select count(*) from user u where u.uid = subscribe.mid" eq 0)
println(formatter.sql)
}
}