mirror of
https://github.com/tursom/TursomServer.git
synced 2025-02-13 21:31:25 +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-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")
|
||||||
|
@ -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 {
|
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")
|
||||||
}
|
}
|
||||||
|
@ -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
|
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()
|
|
||||||
}
|
}
|
@ -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()
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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]
|
||||||
|
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 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()
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
|
)
|
||||||
|
|
||||||
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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() } }
|
||||||
|
|
||||||
|
@ -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>()")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
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"))
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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