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-xml")
include("ts-core:ts-async-http") include("ts-core:ts-async-http")
include("ts-core:ts-proxy") include("ts-core:ts-proxy")
include("ts-core:ts-proxy-jdk")
include("ts-core:ts-reflect") include("ts-core:ts-reflect")
include("ts-core:ts-reflectasm")
include("ts-socket") include("ts-socket")
include("ts-web") include("ts-web")
include("ts-web:ts-web-netty") 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 { dependencies {
api(project(":ts-core")) 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") implementation("org.apache.commons", "commons-lang3", "3.8.1")
testApi(group = "junit", name = "junit", version = "4.13.2") 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 package cn.tursom.proxy
import cn.tursom.core.uncheckedCast import cn.tursom.core.uncheckedCast
import net.sf.cglib.proxy.Enhancer
import java.util.concurrent.ConcurrentHashMap
interface Proxy<out T : ProxyMethod> : Iterable<T> { object Proxy {
data class Result<out R>( private val cache = ConcurrentHashMap<Class<*>, Class<*>>()
val result: R,
val success: Boolean = false,
)
companion object { private fun <T> getTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
val failed: Result<*> = Result<Any?>(null, false) val enhancer = Enhancer()
fun <R> of(): Result<R?> { enhancer.setSuperclass(clazz)
return of(null) enhancer.setCallbackType(ProxyInterceptor::class.java)
} enhancer.setCallbackFilter { 0 }
enhancer.createClass()
}.uncheckedCast()
/** operator fun <T> get(clazz: Class<T>, builder: (Class<T>) -> T): Pair<T, MutableProxyContainer> {
* 返回一个临时使用的 Result 对象 val target = getTarget(clazz)
* 因为是临时对象所以不要把这个对象放到任何当前函数堆栈以外的地方 val container = ListProxyContainer()
* 如果要长期储存对象请 new Result synchronized(target) {
*/ Enhancer.registerCallbacks(target, arrayOf(ProxyInterceptor(container)))
fun <R> of(result: R): Result<R> { return builder(target) to container
return Result(result, true)
}
fun <R> failed(): Result<R> {
return failed.uncheckedCast()
} }
} }
}
inline fun <T : ProxyMethod> Proxy<T>.forEachProxy(action: (T) -> Unit) { inline fun <reified T> get() = get(T::class.java)
for (t in this) { inline fun <reified T> get(
action(t) 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> { operator fun <T> get(clazz: Class<T>): Pair<T, MutableProxyContainer> = get(clazz, Class<T>::newInstance)
for (t in this) {
val result = action(t) operator fun <T> get(
if (result != null && result.success) { clazz: Class<T>,
return result 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 package cn.tursom.proxy
import cn.tursom.proxy.annotation.ForEachProxy import cn.tursom.core.uncheckedCast
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)
}
data class ProxyResult<out R>(
val result: R,
val success: Boolean = false,
) {
companion object { companion object {
private val errMsgSearchList = arrayOf("%M", "%B", "%A") val failed: ProxyResult<*> = ProxyResult<Any?>(null, false)
fun <R> of(): ProxyResult<R?> {
fun onForFirstProxy(forFirstProxy: ForFirstProxy) = { o: Any, m: Method, a: Array<out Any?>, p: MethodProxy -> return of(null)
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()
})
} }
private fun onForFirstProxy( /**
obj: Any, * 返回一个临时使用的 Result 对象
method: Method, * 因为是临时对象所以不要把这个对象放到任何当前函数堆栈以外的地方
args: Array<out Any?>, * 如果要长期储存对象请 new Result
proxy: MethodProxy?, */
forFirstProxy: ForFirstProxy, fun <R> of(result: R): ProxyResult<R> {
classes: Collection<Class<*>>, return ProxyResult(result, true)
): 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
} }
private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) { fun <R> failed(): ProxyResult<R> {
0 -> emptyList() return failed.uncheckedCast()
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?>()
} }
} }
}
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 import java.util.concurrent.ConcurrentHashMap
object ProxyContainerHandlerCache { 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() ConcurrentHashMap()
val callSuper = { obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy -> val callSuper = { obj: Any, _: ProxyContainer, _: Method, args: Array<out Any?>, proxy: MethodProxy ->
Proxy.of<Any?>(proxy.invokeSuper(obj, args)) 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] 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 handlerMap[method] = onProxy ?: callSuper
} }
} }

View File

@ -6,7 +6,9 @@ import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.* import java.util.*
class ProxyInterceptor : MethodInterceptor { class ProxyInterceptor(
private val container: ProxyContainer = ListProxyContainer(),
) : MethodInterceptor {
companion object { companion object {
private val HANDLE_DEQUE_THREAD_LOCAL = ThreadLocal<ArrayDeque<Any>>() private val HANDLE_DEQUE_THREAD_LOCAL = ThreadLocal<ArrayDeque<Any>>()
private val parameterTypes = arrayOf(Method::class.java, Array<Any>::class.java, MethodProxy::class.java) 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)) return method.name == name && parameterTypes.contentEquals(getParameterTypes(method))
} }
private fun isOnProxyMethod(method: Method): Boolean { fun isOnProxyMethod(method: Method): Boolean {
return equalsMethod(method, "onProxy", parameterTypes) 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) @Throws(Throwable::class)
override fun intercept(obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy): Any? { override fun intercept(obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy): Any? {
push(obj) if (!isOnProxyMethod(method)) {
return try { val result = ProxyRunner.onProxy(obj, container, method, args, proxy)
if (obj is ProxyContainer<*> && !isOnProxyMethod(method)) { if (result != null && result.success) {
val result = obj.onProxy(method, args, proxy) return result.result
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 { interface ProxyMethod {
@Throws(Throwable::class) @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 selfMethod: Method
val handlerCacheMap = getHandlerCacheMap(javaClass) val handlerCacheMap = getHandlerCacheMap(javaClass)
val methodResult = handlerCacheMap[method] val methodResult = handlerCacheMap[method]
if (methodResult != null) { if (methodResult != null) {
return if (methodResult.success) { return if (methodResult.success) {
Proxy.of(methodResult.result(this, *args)) ProxyResult.of(methodResult.result(this, *args))
} else { } else {
Proxy.failed<Any>() ProxyResult.failed<Any>()
} }
} }
try { try {
@ -36,19 +36,19 @@ interface ProxyMethod {
} }
selfMethod = javaClass.getMethod(methodName, *method.parameterTypes) selfMethod = javaClass.getMethod(methodName, *method.parameterTypes)
selfMethod.isAccessible = true selfMethod.isAccessible = true
handlerCacheMap[method] = Proxy.Result(selfMethod, true) handlerCacheMap[method] = ProxyResult(selfMethod, true)
} catch (e: Exception) { } catch (e: Exception) {
handlerCacheMap[method] = Proxy.failed() handlerCacheMap[method] = ProxyResult.failed()
return Proxy.failed<Any>() return ProxyResult.failed<Any>()
} }
return Proxy.of<Any>(selfMethod(this, *args)) return ProxyResult.of<Any>(selfMethod(this, *args))
} }
companion object { 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() 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] var handlerCacheMap = handlerCacheMapMap[type]
if (handlerCacheMap == null) synchronized(handlerCacheMapMap) { if (handlerCacheMap == null) synchronized(handlerCacheMapMap) {
handlerCacheMap = handlerCacheMapMap[type] 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 must: Boolean = false,
val errMsg: String = "", val errMsg: String = "",
val errClass: KClass<out RuntimeException> = RuntimeException::class, 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.Example.GetA
import cn.tursom.proxy.annotation.ForEachProxy import cn.tursom.proxy.annotation.ForEachProxy
import net.sf.cglib.proxy.Enhancer
import org.junit.Test import org.junit.Test
class Example { class Example {
open class TestClass protected constructor() : ProxyContainer<ProxyMethod> { open class TestClass protected constructor() {
@get:ForEachProxy @get:ForEachProxy
open val a: Int = 0 open val a: Int = 0
override val proxy = ListProxy<ProxyMethod>()
} }
fun interface GetA : ProxyMethod { fun interface GetA : ProxyMethod {
fun getA(): Int fun getA(): Int
} }
private val enhancer = Enhancer()
init {
enhancer.setSuperclass(TestClass::class.java)
enhancer.setCallback(ProxyInterceptor())
}
@Test @Test
fun test() { fun test() {
val testClass = enhancer.create() as TestClass repeat(3) {
testClass.proxy.addProxy(GetA { val (t, container) = Proxy.get<TestClass>()
println("on proxy method") container.addProxy(GetA {
0 println("on proxy method")
}) 0
})
println(testClass.javaClass) println(t.javaClass)
println(testClass.a) println(t.a)
}
} }
} }

View File

@ -6,93 +6,129 @@ import cn.tursom.core.uncheckedCast
import java.lang.reflect.Method import java.lang.reflect.Method
inline fun <R> Class<*>.getDeclaredMethod( inline fun <R> Class<*>.getDeclaredMethod(
returnType: Class<*>, returnType: Class<*>,
getMethod: Class<*>.() -> Method?, getMethod: Class<*>.() -> Method?,
staticReturn: (method: Method) -> R, onGetMethod: (Method) -> Unit = {},
staticReturn: (method: Method) -> R,
): R? { ): R? {
val method = this.getDeclaredMethod(returnType, false, getMethod) val method = this.getDeclaredMethod(returnType, false, getMethod)
if (method != null) return staticReturn(method) if (method != null) {
return null onGetMethod(method)
return staticReturn(method)
}
return null
} }
inline fun <reified R : Any> Any.getMethod( inline fun <reified R : Any> Any.getMethod(
name: String, name: String,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name)
): (() -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> },
{ method(this).uncheckedCast() } ): (() -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod(name, returnType, getMethod) { method(this).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod(name, returnType, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1> Any.getMethod1( inline fun <reified R : Any, reified T1> Any.getMethod1(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type)
): ((T1) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> },
{ method(this, it).uncheckedCast() } ): ((T1) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod1(name, returnType, arg1Type, getMethod) { method(this, it).uncheckedCast() }
} ?: clazz.getStaticDeclaredMethod1(name, returnType, arg1Type, onGetMethod, getMethod)
inline fun <reified R : Any, reified T1, reified T2> Any.getMethod2( inline fun <reified R : Any, reified T1, reified T2> Any.getMethod2(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type)
): ((T1, T2) -> R)? = clazz.getDeclaredMethod(returnType, getMethod) { method -> },
{ v1, v2 -> method(this, v1, v2).uncheckedCast() } ): ((T1, T2) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod2(name, returnType, arg1Type, arg2Type, getMethod) { 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( inline fun <reified R : Any, reified T1, reified T2, reified T3> Any.getMethod3(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type) 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() } ): ((T1, T2, T3) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod3(name, returnType, arg1Type, arg2Type, arg3Type, getMethod) { 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( inline fun <reified R : Any, reified T1, reified T2, reified T3, reified T4> Any.getMethod4(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java, arg4Type: Class<T4> = T4::class.java,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) 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() } ): ((T1, T2, T3, T4) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod4(name, returnType, arg1Type, arg2Type, arg3Type, arg4Type, getMethod) { 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( inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Any.getMethod5(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java, arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java, arg5Type: Class<T5> = T5::class.java,
clazz: Class<*> = javaClass, clazz: Class<*> = javaClass,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type) 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() } ): ((T1, T2, T3, T4, T5) -> R)? = clazz.getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
} ?: clazz.getStaticDeclaredMethod5(name, returnType, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type, getMethod) { 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 import java.lang.reflect.Method
inline fun <This, reified R> Class<*>.getMethod( inline fun <This, reified R> Class<*>.getMethod(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
getMethod: Class<*>.() -> Method? = { getMethodFully(name) }, onGetMethod: (Method) -> Unit = {},
): (This.() -> R)? = getDeclaredMethod(returnType, getMethod) { method -> getMethod: Class<*>.() -> Method? = {
{ method(this).uncheckedCast() } getMethodFully(name)
},
): (This.() -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this).uncheckedCast() }
} }
inline fun <This, reified R, reified T1> Class<*>.getMethod1( inline fun <This, reified R, reified T1> Class<*>.getMethod1(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java, arg1Type: Class<in T1> = T1::class.java,
getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type) }, onGetMethod: (Method) -> Unit = {},
): (This.(T1) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type) },
{ method(this, it).uncheckedCast() } ): (This.(T1) -> R)? = getDeclaredMethod(returnType, getMethod, onGetMethod) { method ->
{ method(this, it).uncheckedCast() }
} }
inline fun <This, reified R, reified T1, reified T2> Class<*>.getMethod2( inline fun <This, reified R, reified T1, reified T2> Class<*>.getMethod2(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java, arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java, arg2Type: Class<in T2> = T2::class.java,
getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type, arg2Type) }, onGetMethod: (Method) -> Unit = {},
): (This.(T1, T2) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> getMethod: Class<*>.() -> Method? = { getMethodFully(name, arg1Type, arg2Type) },
{ v1, v2 -> method(this, v1, v2).uncheckedCast() } ): (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( inline fun <This, reified R, reified T1, reified T2, reified T3> Class<*>.getMethod3(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java, arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java, arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java, arg3Type: Class<in T3> = T3::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type) 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() } ): (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( inline fun <This, reified R, reified T1, reified T2, reified T3, reified T4> Class<*>.getMethod4(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java, arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java, arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java, arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java, arg4Type: Class<in T4> = T4::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) 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() } ): (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( inline fun <This, reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Class<*>.getMethod5(
name: String, name: String,
returnType: Class<out R> = R::class.java, returnType: Class<out R> = R::class.java,
arg1Type: Class<in T1> = T1::class.java, arg1Type: Class<in T1> = T1::class.java,
arg2Type: Class<in T2> = T2::class.java, arg2Type: Class<in T2> = T2::class.java,
arg3Type: Class<in T3> = T3::class.java, arg3Type: Class<in T3> = T3::class.java,
arg4Type: Class<in T4> = T4::class.java, arg4Type: Class<in T4> = T4::class.java,
arg5Type: Class<in T5> = T5::class.java, arg5Type: Class<in T5> = T5::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
): (This.(T1, T2, T3, T4, T5) -> R)? = getDeclaredMethod(returnType, getMethod) { method -> },
{ v1, v2, v3, v4, v5 -> method(this, v1, v2, v3, v4, v5).uncheckedCast() } ): (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.allMethodsSequence
import cn.tursom.core.companionObjectInstanceOrNull import cn.tursom.core.companionObjectInstanceOrNull
import cn.tursom.core.sequence.cache
import cn.tursom.core.uncheckedCast import cn.tursom.core.uncheckedCast
import java.lang.reflect.Method import java.lang.reflect.Method
inline fun <reified T> getType() = T::class.java inline fun <reified T> getType() = T::class.java
fun main() { infix fun Class<*>.canCast(target: Class<*>): Boolean {
println(Int::class.java canCast getType<Byte>()) return (target == Any::class.java || this == target) || (
println(Int::class.java canCast getType<Int>()) 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 { infix fun Array<out Class<*>>.match(types: Array<out Class<*>>): Boolean {
return (target == Any::class.java || this == target) || ( forEachIndexed { index, clazz ->
(this == Void.TYPE || this == Void::class.java) && if (!(types[index] canCast clazz)) return false
(target == Unit::class.java || target == Void.TYPE || target == Void::class.java) }
) || ( return true
(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)
} }
private fun Method.match(name: String, vararg type: Class<*>): Boolean { private fun Method.match(name: String, vararg type: Class<*>): Boolean {
if (this.name != name) return false if (this.name != name) return false
if (this.parameterTypes.size != type.size) return false if (this.parameterTypes.size != type.size) return false
this.parameterTypes.forEachIndexed { index, clazz -> return this.parameterTypes match type
if (!(type[index] canCast clazz)) return false
}
return true
} }
fun Class<*>.getFirstMatchMethod( fun Class<*>.getFirstMatchMethod(
name: String, name: String,
vararg type: Class<*>, vararg type: Class<*>,
): Method? { ): Method? {
allMethodsSequence.forEach { method -> allMethodsSequence.forEach { method ->
if (method.match(name, *type)) { if (method.match(name, type = type)) {
return method return method
}
} }
return null }
return null
} }
fun Class<*>.getMethodFully( fun Class<*>.getMethodFully(
name: String, name: String,
vararg type: Class<*>, vararg type: Class<*>,
): Method? { ): Method? {
val scanMethod = scanMethod(name, *type) val scanMethod = scanMethod(name, type = type)
return (scanMethod.firstOrNull { method -> return scanMethod.firstOrNull { method ->
method.parameterTypes.forEachIndexed { index, clazz -> method.parameterTypes.forEachIndexed { index, clazz ->
if (type[index] != clazz) return@firstOrNull false if (type[index] != clazz) return@firstOrNull false
} }
true true
} ?: scanMethod.firstOrNull()) } ?: scanMethod.firstOrNull()
} }
fun Class<*>.scanMethod( fun Class<*>.scanMethod(
name: String, name: String,
vararg type: Class<*>, vararg type: Class<*>,
): List<Method> { ): Sequence<Method> {
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
return buildList { return allMethodsSequence.filter { method ->
allMethodsSequence.forEach { method -> method.match(name, type = type)
if (method.match(name, *type)) add(method) }.cache()
}
}
} }
inline fun Class<*>.getDeclaredMethod( inline fun Class<*>.getDeclaredMethod(
returnType: Class<*>, returnType: Class<*>,
isStatic: Boolean = true, isStatic: Boolean = true,
getMethod: Class<*>.() -> Method?, getMethod: Class<*>.() -> Method?,
) = try { ) = try {
val method = getMethod() val method = getMethod()
method?.isAccessible = true method?.isAccessible = true
if (method != null && method.isStatic() == isStatic && method.returnType canCast returnType) method if (method != null && method.isStatic() == isStatic && method.returnType canCast returnType) method
else null else null
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
inline fun <R> Class<*>.getStaticDeclaredMethod( inline fun <R> Class<*>.getStaticDeclaredMethod(
returnType: Class<*>, returnType: Class<*>,
getMethod: Class<*>.() -> Method?, getMethod: Class<*>.() -> Method?,
staticReturn: (method: Method, companionObjectInstance: Any?) -> R, onGetMethod: (Method) -> Unit = {},
staticReturn: (method: Method, companionObjectInstance: Any?) -> R,
): R? { ): R? {
val method = getDeclaredMethod(returnType, true, getMethod) val method = getDeclaredMethod(returnType, true, getMethod)
if (method != null) return staticReturn(method, null) if (method != null) {
onGetMethod(method)
return staticReturn(method, null)
}
val companionObjectInstance = kotlin.companionObjectInstanceOrNull ?: return null val companionObjectInstance = kotlin.companionObjectInstanceOrNull ?: return null
val companionObjectClazz = companionObjectInstance.javaClass val companionObjectClazz = companionObjectInstance.javaClass
val companionMethod = companionObjectClazz.getDeclaredMethod(returnType, false, getMethod) val companionMethod = companionObjectClazz.getDeclaredMethod(returnType, false, getMethod)
if (companionMethod != null) return staticReturn(companionMethod, companionObjectInstance) if (companionMethod != null) {
onGetMethod(companionMethod)
return staticReturn(companionMethod, companionObjectInstance)
}
return null return null
} }
inline fun <reified R : Any> Class<*>.getStaticDeclaredMethod( inline fun <reified R : Any> Class<*>.getStaticDeclaredMethod(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name)
},
): (() -> R)? = getStaticDeclaredMethod( ): (() -> R)? = getStaticDeclaredMethod(
returnType, getMethod returnType, getMethod, onGetMethod
) { method, companion -> { method(companion).uncheckedCast() } } ) { method, companion -> { method(companion).uncheckedCast() } }
inline fun <reified R, reified T1> Class<*>.getStaticDeclaredMethod1( inline fun <reified R, reified T1> Class<*>.getStaticDeclaredMethod1(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type)
},
): ((T1) -> R)? = getStaticDeclaredMethod( ): ((T1) -> R)? = getStaticDeclaredMethod(
returnType, getMethod returnType, getMethod, onGetMethod
) { method, companion -> { v1 -> method(companion, v1).uncheckedCast() } } ) { method, companion -> { v1 -> method(companion, v1).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2> Class<*>.getStaticDeclaredMethod2( inline fun <reified R, reified T1, reified T2> Class<*>.getStaticDeclaredMethod2(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type)
},
): ((T1, T2) -> R)? = getStaticDeclaredMethod( ): ((T1, T2) -> R)? = getStaticDeclaredMethod(
returnType, getMethod returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2 -> method(companion, v1, v2).uncheckedCast() } } ) { method, companion -> { v1, v2 -> method(companion, v1, v2).uncheckedCast() } }
inline fun <reified R, reified T1, reified T2, reified T3> Class<*>.getStaticDeclaredMethod3( inline fun <reified R, reified T1, reified T2, reified T3> Class<*>.getStaticDeclaredMethod3(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type, arg3Type)
},
): ((T1, T2, T3) -> R)? = getStaticDeclaredMethod( ): ((T1, T2, T3) -> R)? = getStaticDeclaredMethod(
returnType, getMethod returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3 -> method(companion, v1, v2, v3).uncheckedCast() } } ) { 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( inline fun <reified R, reified T1, reified T2, reified T3, reified T4> Class<*>.getStaticDeclaredMethod4(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java, arg4Type: Class<T4> = T4::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type)
},
): ((T1, T2, T3, T4) -> R)? = getStaticDeclaredMethod( ): ((T1, T2, T3, T4) -> R)? = getStaticDeclaredMethod(
returnType, getMethod returnType, getMethod, onGetMethod
) { method, companion -> { v1, v2, v3, v4 -> method(companion, v1, v2, v3, v4).uncheckedCast() } } ) { 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( inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5> Class<*>.getStaticDeclaredMethod5(
name: String, name: String,
returnType: Class<R> = R::class.java, returnType: Class<R> = R::class.java,
arg1Type: Class<T1> = T1::class.java, arg1Type: Class<T1> = T1::class.java,
arg2Type: Class<T2> = T2::class.java, arg2Type: Class<T2> = T2::class.java,
arg3Type: Class<T3> = T3::class.java, arg3Type: Class<T3> = T3::class.java,
arg4Type: Class<T4> = T4::class.java, arg4Type: Class<T4> = T4::class.java,
arg5Type: Class<T5> = T5::class.java, arg5Type: Class<T5> = T5::class.java,
getMethod: Class<*>.() -> Method? = { onGetMethod: (Method) -> Unit = {},
getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type) getMethod: Class<*>.() -> Method? = {
}, getMethodFully(name, arg1Type, arg2Type, arg3Type, arg4Type, arg5Type)
},
): ((T1, T2, T3, T4, T5) -> R)? = getStaticDeclaredMethod( ): ((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() } } ) { 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 import kotlin.reflect.KClass
object InstantAllocator { 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) @Throws(NoSuchMethodException::class)
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe) operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
@Throws(NoSuchMethodException::class) @Throws(NoSuchMethodException::class)
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe) inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
@Throws(NoSuchMethodException::class) @Throws(NoSuchMethodException::class)
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe) operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
@Throws(NoSuchMethodException::class) @Throws(NoSuchMethodException::class)
operator fun <T> get(clazz: Class<out T>, unsafe: Boolean = true): T { operator fun <T> get(clazz: Class<out T>, unsafe: Boolean = true): T {
return when (allocateFunctionMap[clazz]) { return when (allocateFunctionMap[clazz]) {
null -> try { null -> try {
val newInstance = clazz.newInstance() val newInstance = clazz.newInstance()
allocateFunctionMap[clazz] = AllocateFunction.INSTANCE allocateFunctionMap[clazz] = AllocateFunction.INSTANCE
newInstance newInstance
} catch (e: Exception) { } catch (e: Exception) {
val kClass = clazz.kotlin val kClass = clazz.kotlin
val objectInstance = kClass.objectInstance val objectInstance = kClass.objectInstance
if (objectInstance != null) { if (objectInstance != null) {
allocateFunctionMap[clazz] = AllocateFunction.KOBJECT allocateFunctionMap[clazz] = AllocateFunction.KOBJECT
objectInstance objectInstance
} else if (unsafe) try { } else if (unsafe) try {
allocateFunctionMap[clazz] = AllocateFunction.UNSAFE allocateFunctionMap[clazz] = AllocateFunction.UNSAFE
@OptIn(UncheckedCast::class) @OptIn(UncheckedCast::class)
Unsafe.unsafe.allocateInstance(clazz).cast<T>() Unsafe.unsafe.allocateInstance(clazz).cast<T>()
} catch (e: Exception) { } catch (e: Exception) {
allocateFunctionMap[clazz] = AllocateFunction.NONE allocateFunctionMap[clazz] = AllocateFunction.NONE
throw NoSuchMethodException("${clazz.name}:<init>()") throw NoSuchMethodException("${clazz.name}:<init>()")
} else { } else {
throw NoSuchMethodException("${clazz.name}:<init>()") 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>()")
} }
}
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 { private val fieldModifiersField: Field? = try {
Field::class.java.getDeclaredField("modifiers").apply { Field::class.java.getDeclaredField("modifiers").apply {
isAccessible = true isAccessible = true
} }
} catch (e: Throwable) { } catch (e: Throwable) {
null null
} }
var fieldModifiers: (Field, Int) -> Unit = { field, modifer -> var fieldModifiers: (Field, Int) -> Unit = { field, modifier ->
fieldModifiersField!!.set(field, modifer) fieldModifiersField!!.set(field, modifier)
} }
var Field.public: Boolean var Field.public: Boolean
get() = Modifier.isPublic(this.modifiers) get() = Modifier.isPublic(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.PUBLIC val modifier = Modifier.PUBLIC
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.private: Boolean var Field.private: Boolean
get() = Modifier.isPrivate(this.modifiers) get() = Modifier.isPrivate(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.PRIVATE val modifier = Modifier.PRIVATE
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.protected: Boolean var Field.protected: Boolean
get() = Modifier.isProtected(this.modifiers) get() = Modifier.isProtected(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.PROTECTED val modifier = Modifier.PROTECTED
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.static: Boolean var Field.static: Boolean
get() = Modifier.isStatic(this.modifiers) get() = Modifier.isStatic(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.STATIC val modifier = Modifier.STATIC
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.final: Boolean var Field.final: Boolean
get() = Modifier.isFinal(this.modifiers) get() = Modifier.isFinal(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.FINAL val modifier = Modifier.FINAL
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.synchronized: Boolean var Field.synchronized: Boolean
get() = Modifier.isSynchronized(this.modifiers) get() = Modifier.isSynchronized(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.SYNCHRONIZED val modifier = Modifier.SYNCHRONIZED
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.volatile: Boolean var Field.volatile: Boolean
get() = Modifier.isVolatile(this.modifiers) get() = Modifier.isVolatile(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.VOLATILE val modifier = Modifier.VOLATILE
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.transient: Boolean var Field.transient: Boolean
get() = Modifier.isTransient(this.modifiers) get() = Modifier.isTransient(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.TRANSIENT val modifier = Modifier.TRANSIENT
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.native: Boolean var Field.native: Boolean
get() = Modifier.isNative(this.modifiers) get() = Modifier.isNative(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.NATIVE val modifier = Modifier.NATIVE
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.`interface`: Boolean var Field.`interface`: Boolean
get() = Modifier.isInterface(this.modifiers) get() = Modifier.isInterface(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.INTERFACE val modifier = Modifier.INTERFACE
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.abstract: Boolean var Field.abstract: Boolean
get() = Modifier.isAbstract(this.modifiers) get() = Modifier.isAbstract(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.ABSTRACT val modifier = Modifier.ABSTRACT
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
var Field.strict: Boolean var Field.strict: Boolean
get() = Modifier.isStrict(this.modifiers) get() = Modifier.isStrict(this.modifiers)
set(value) { set(value) {
val modifier = Modifier.STRICT val modifier = Modifier.STRICT
fieldModifiers( fieldModifiers(
this, this,
if (value) { if (value) {
modifiers or modifier modifiers or modifier
} else { } else {
modifiers and modifier.inv() modifiers and modifier.inv()
} }
) )
} }
fun Member.isPublic(): Boolean { fun Member.isPublic(): Boolean {
return Modifier.isPublic(this.modifiers) return Modifier.isPublic(this.modifiers)
} }
fun Member.isPrivate(): Boolean { fun Member.isPrivate(): Boolean {
return Modifier.isPrivate(this.modifiers) return Modifier.isPrivate(this.modifiers)
} }
fun Member.isProtected(): Boolean { fun Member.isProtected(): Boolean {
return Modifier.isProtected(this.modifiers) return Modifier.isProtected(this.modifiers)
} }
fun Member.isStatic(): Boolean { fun Member.isStatic(): Boolean {
return Modifier.isStatic(this.modifiers) return Modifier.isStatic(this.modifiers)
} }
fun Member.isFinal(): Boolean { fun Member.isFinal(): Boolean {
return Modifier.isFinal(this.modifiers) return Modifier.isFinal(this.modifiers)
} }
fun Member.isSynchronized(): Boolean { fun Member.isSynchronized(): Boolean {
return Modifier.isSynchronized(this.modifiers) return Modifier.isSynchronized(this.modifiers)
} }
fun Member.isVolatile(): Boolean { fun Member.isVolatile(): Boolean {
return Modifier.isVolatile(this.modifiers) return Modifier.isVolatile(this.modifiers)
} }
fun Member.isTransient(): Boolean { fun Member.isTransient(): Boolean {
return Modifier.isTransient(this.modifiers) return Modifier.isTransient(this.modifiers)
} }
fun Member.isNative(): Boolean { fun Member.isNative(): Boolean {
return Modifier.isNative(this.modifiers) return Modifier.isNative(this.modifiers)
} }
fun Member.isInterface(): Boolean { fun Member.isInterface(): Boolean {
return Modifier.isInterface(this.modifiers) return Modifier.isInterface(this.modifiers)
} }
fun Member.isAbstract(): Boolean { fun Member.isAbstract(): Boolean {
return Modifier.isAbstract(this.modifiers) return Modifier.isAbstract(this.modifiers)
} }
fun Member.isStrict(): Boolean { fun Member.isStrict(): Boolean {
return Modifier.isStrict(this.modifiers) return Modifier.isStrict(this.modifiers)
} }
val Class<*>.isPublic: Boolean val Class<*>.isPublic: Boolean
get() = Modifier.isPublic(this.modifiers) get() = Modifier.isPublic(this.modifiers)
val Class<*>.isPrivate: Boolean val Class<*>.isPrivate: Boolean
get() = Modifier.isPrivate(this.modifiers) get() = Modifier.isPrivate(this.modifiers)
val Class<*>.isProtected: Boolean val Class<*>.isProtected: Boolean
get() = Modifier.isProtected(this.modifiers) get() = Modifier.isProtected(this.modifiers)
val Class<*>.isStatic: Boolean val Class<*>.isStatic: Boolean
get() = Modifier.isStatic(this.modifiers) get() = Modifier.isStatic(this.modifiers)
val Class<*>.isFinal: Boolean val Class<*>.isFinal: Boolean
get() = Modifier.isFinal(this.modifiers) get() = Modifier.isFinal(this.modifiers)
val Class<*>.isSynchronized: Boolean val Class<*>.isSynchronized: Boolean
get() = Modifier.isSynchronized(this.modifiers) get() = Modifier.isSynchronized(this.modifiers)
val Class<*>.isVolatile: Boolean val Class<*>.isVolatile: Boolean
get() = Modifier.isVolatile(this.modifiers) get() = Modifier.isVolatile(this.modifiers)
val Class<*>.isTransient: Boolean val Class<*>.isTransient: Boolean
get() = Modifier.isTransient(this.modifiers) get() = Modifier.isTransient(this.modifiers)
val Class<*>.isNative: Boolean val Class<*>.isNative: Boolean
get() = Modifier.isNative(this.modifiers) get() = Modifier.isNative(this.modifiers)
//val Class<*>.isInterface: Boolean //val Class<*>.isInterface: Boolean
// get() = Modifier.isInterface(this.modifiers) // get() = Modifier.isInterface(this.modifiers)
val Class<*>.isAbstract val Class<*>.isAbstract
get() = Modifier.isAbstract(this.modifiers) get() = Modifier.isAbstract(this.modifiers)
val Class<*>.isStrict 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 import java.lang.reflect.Method
interface MethodFilter { interface MethodFilter {
fun filterMethod(clazz: Class<*>): Sequence<Method> fun filterMethod(clazz: Class<*>): Sequence<Method>
companion object companion object
} }
class Arg1MethodFilter<R>( class Arg1MethodFilter<R>(
val prevFilter: ReturnTypeMethodFilter<R>, val prevFilter: ReturnTypeMethodFilter<R>,
) : MethodFilter { ) : MethodFilter {
override fun filterMethod(clazz: Class<*>): Sequence<Method> { override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return prevFilter.filterMethod(clazz).filter { method -> return prevFilter.filterMethod(clazz).filter { method ->
method.parameterCount == 1 method.parameterCount == 1
}
} }
}
fun <T> filter(clazz: Class<T>): Sequence<T.() -> R> { fun <T> filter(clazz: Class<T>): Sequence<T.() -> R> {
return filterMethod(clazz).map { return filterMethod(clazz).map {
{ {
it.invoke(this) as R it.invoke(this) as R
} }
}
} }
}
fun filter(obj: Any): Sequence<() -> R> { fun filter(obj: Any): Sequence<() -> R> {
return filterMethod(obj.javaClass).map { return filterMethod(obj.javaClass).map {
{ {
it.invoke(obj) as R it.invoke(obj) as R
} }
}
} }
}
} }

View File

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

View File

@ -4,19 +4,19 @@ import cn.tursom.core.allMethodsSequence
import java.lang.reflect.Method import java.lang.reflect.Method
class ReturnTypeMethodFilter<R>( class ReturnTypeMethodFilter<R>(
val returnType: Class<R>, val returnType: Class<R>,
) : MethodFilter { ) : MethodFilter {
override fun filterMethod(clazz: Class<*>): Sequence<Method> { override fun filterMethod(clazz: Class<*>): Sequence<Method> {
return clazz.allMethodsSequence.filter { method -> return clazz.allMethodsSequence.filter { method ->
val methodReturnType = if ( val methodReturnType = if (
method.returnType == Void.TYPE || method.returnType == Void.TYPE ||
method.returnType == Void::class.java method.returnType == Void::class.java
) Unit::class.java else method.returnType ) Unit::class.java else method.returnType
returnType.isAssignableFrom(methodReturnType) returnType.isAssignableFrom(methodReturnType)
}
} }
}
companion object companion object
} }
inline fun <reified R> MethodFilter.Companion.returnType() = ReturnTypeMethodFilter(R::class.java) 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) operator fun Class<*>.contains(obj: Any): Boolean = isInstance(obj)
fun <T> Class<*>.getStaticField(name: String): T? { fun <T> Class<*>.getStaticField(name: String): T? {
val staticField = getDeclaredField(name) val staticField = getDeclaredField(name)
if (staticField.isStatic()) { if (staticField.isStatic()) {
staticField.isAccessible = true staticField.isAccessible = true
return staticField.get(null).uncheckedCast() return staticField.get(null).uncheckedCast()
} }
val companionObjectInstance = kotlin.companionObjectInstanceOrNull val companionObjectInstance = kotlin.companionObjectInstanceOrNull
if (companionObjectInstance != null) { if (companionObjectInstance != null) {
return companionObjectInstance[name]?.uncheckedCast() return companionObjectInstance[name]?.uncheckedCast()
} }
return null return null
} }
inline fun <reified C : Any, T> getStaticField(name: String): T? { 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") @Suppress("UNCHECKED_CAST")
fun <T : Enum<out T>> Class<out T>.valueOf(value: String): T? { fun <T : Enum<out T>> Class<out T>.valueOf(value: String): T? {
var valueOf: Method? = null var valueOf: Method? = null
return try { return try {
valueOf = getDeclaredMethod("valueOf", String::class.java) valueOf = getDeclaredMethod("valueOf", String::class.java)
valueOf.invoke(null, value) as T valueOf.invoke(null, value) as T
} catch (e: Exception) {
try {
valueOf?.invoke(null, value.toUpperCase()) as? T?
} catch (e: Exception) { } catch (e: Exception) {
try { null
valueOf?.invoke(null, value.toUpperCase()) as? T?
} catch (e: Exception) {
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"))
implementation(project(":ts-core:ts-clone")) implementation(project(":ts-core:ts-clone"))
implementation(project(":ts-core:ts-log")) 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") api(group = "org.ktorm", name = "ktorm-core", version = "3.4.1")
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.9") compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.9")
testApi(group = "junit", name = "junit", version = "4.13.2") 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)
}
}