mirror of
https://github.com/tursom/TursomServer.git
synced 2025-02-10 03:40:51 +08:00
update
This commit is contained in:
parent
bf2b15aee8
commit
ebd7f40380
@ -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")
|
||||
|
@ -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)
|
22
ts-core/ts-proxy-jdk/build.gradle.kts
Normal file
22
ts-core/ts-proxy-jdk/build.gradle.kts
Normal 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"
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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]
|
||||
|
111
ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt
Normal file
111
ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt
Normal 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?>()
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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() }
|
||||
}
|
||||
|
||||
|
@ -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() } }
|
||||
|
||||
|
@ -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>()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
ts-core/ts-reflectasm/build.gradle.kts
Normal file
22
ts-core/ts-reflectasm/build.gradle.kts
Normal 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"
|
||||
}
|
@ -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]
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user