diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt new file mode 100644 index 0000000..a336678 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt @@ -0,0 +1,40 @@ +package cn.tursom.proxy + +import cn.tursom.reflect.asm.ReflectAsmUtils +import net.sf.cglib.core.Signature +import net.sf.cglib.proxy.Callback +import net.sf.cglib.proxy.MethodProxy + +object CglibUtil { + fun getFactoryData(clazz: Class<*>): Any? { + val (fieldAccess, i) = ReflectAsmUtils.getField(clazz, "CGLIB\$FACTORY_DATA")!! + return fieldAccess.get(null, i) + } + + fun getCallbackFilter(clazz: Class<*>): Any? { + val field = clazz.getDeclaredField("CGLIB\$CALLBACK_FILTER") + field.isAccessible = true + return field.get(null) + } + + fun findMethodProxy(clazz: Class<*>, signature: Signature): MethodProxy? { + return ReflectAsmUtils.getStaticMethod1( + clazz, + "CGLIB\$findMethodProxy" + )!!(signature) + } + + fun setThreadCallbacks(clazz: Class<*>, callbacks: Array) { + ReflectAsmUtils.getStaticMethod1, Unit?>( + clazz, + "CGLIB\$SET_THREAD_CALLBACKS" + )!!(callbacks) + } + + fun setStaticCallbacks(clazz: Class<*>, callbacks: Array) { + ReflectAsmUtils.getStaticMethod1, Unit?>( + clazz, + "CGLIB\$SET_STATIC_CALLBACKS" + )!!(callbacks) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt index e521f08..9ae2c06 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt @@ -6,27 +6,40 @@ import net.sf.cglib.proxy.Factory import java.util.concurrent.ConcurrentHashMap object Proxy { - val enhancerMap = ConcurrentHashMap, Enhancer>() + object CallSuperException : Exception() + + val callSuper = object : ThreadLocal() { + override fun initialValue(): Boolean = throw CallSuperException + override fun get(): Boolean = try { + super.get() + } catch (_: CallSuperException) { + false + } + } + + var defaultContainer: () -> MutableProxyContainer = { ListProxyContainer() } private val cache = ConcurrentHashMap, Class<*>>() - private fun getTarget(clazz: Class): Class = cache.computeIfAbsent(clazz) { - val enhancer = Enhancer() - enhancerMap[clazz] = enhancer - enhancer.setSuperclass(clazz) - enhancer.setCallbackType(ProxyInterceptor::class.java) - enhancer.setCallbackFilter { 0 } - enhancer.createClass() - }.uncheckedCast() + fun getContainer(obj: Any): ProxyContainer? { + if (obj !is Factory) return null + val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null + return interceptor.container + } - operator fun get( + fun addProxy(obj: Any, proxy: ProxyMethod): Boolean { + val container = getContainer(obj) ?: return false + (container as? MutableProxyContainer)?.addProxy(proxy) ?: return false + return true + } + + inline operator fun get( clazz: Class, + container: MutableProxyContainer = defaultContainer(), builder: (Class) -> T, ): Pair { - val target = getTarget(clazz) - val container = ListProxyContainer() + val target = getCachedTarget(clazz) val obj = builder(target) - obj as Factory - obj.setCallback(0, ProxyInterceptor(container)) + injectCallback(obj as Factory) { container } return obj to container } @@ -34,15 +47,42 @@ object Proxy { inline fun get( argumentTypes: Array>, arguments: Array, - ) = get(T::class.java, argumentTypes, arguments) + container: MutableProxyContainer = defaultContainer(), + ) = get(T::class.java, argumentTypes, arguments, container) - operator fun get(clazz: Class) = get(clazz, Class::newInstance) + operator fun get(clazz: Class, container: MutableProxyContainer = defaultContainer()) = + get(clazz, container, Class::newInstance) operator fun get( clazz: Class, argumentTypes: Array>, arguments: Array, - ) = get(clazz) { + container: MutableProxyContainer = defaultContainer(), + ) = get(clazz, container) { it.getConstructor(*argumentTypes).newInstance(*arguments) } -} \ No newline at end of file + + fun newEnhancer(clazz: Class, vararg interfaces: Class<*>): Enhancer { + val enhancer = Enhancer() + enhancer.setSuperclass(clazz) + if (interfaces.isNotEmpty()) { + enhancer.setInterfaces(interfaces) + } + enhancer.setCallbackType(ProxyInterceptor::class.java) + enhancer.setCallbackFilter { 0 } + return enhancer + } + + @JvmOverloads + inline fun injectCallback(obj: Any, container: () -> ProxyContainer = { defaultContainer() }): ProxyContainer { + obj as Factory + if (obj.getCallback(0) == null || obj.getCallback(0) == ProxyDispatcher) { + obj.setCallback(0, ProxyInterceptor(container())) + } + return (obj.getCallback(0) as ProxyInterceptor).container + } + + fun getCachedTarget(clazz: Class): Class = cache.computeIfAbsent(clazz) { + newEnhancer(clazz).createClass() + }.uncheckedCast() +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainerHandlerCache.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainerHandlerCache.kt deleted file mode 100644 index 1ac35a0..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainerHandlerCache.kt +++ /dev/null @@ -1,25 +0,0 @@ -package cn.tursom.proxy - -import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Method -import java.util.concurrent.ConcurrentHashMap - -object ProxyContainerHandlerCache { - private val handlerMap: MutableMap, MethodProxy) -> ProxyResult> = - ConcurrentHashMap() - val callSuper = { obj: Any, _: ProxyContainer, _: Method, args: Array, proxy: MethodProxy -> - ProxyResult.of(proxy.invokeSuper(obj, args)) - } - val empty = { _: Any, _: ProxyContainer, _: Method, _: Array, _: MethodProxy -> ProxyResult.failed() } - - fun getHandler(method: MethodProxy): ((Any, ProxyContainer, Method, Array, MethodProxy) -> ProxyResult)? { - return handlerMap[method] - } - - fun setHandler( - method: MethodProxy, - onProxy: ((Any, ProxyContainer, Method, Array, MethodProxy) -> ProxyResult)?, - ) { - handlerMap[method] = onProxy ?: callSuper - } -} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt new file mode 100644 index 0000000..eec44db --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt @@ -0,0 +1,12 @@ +package cn.tursom.proxy + +import net.sf.cglib.proxy.MethodInterceptor +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +object ProxyDispatcher : MethodInterceptor { + override fun intercept(obj: Any, method: Method, args: Array, proxy: MethodProxy): Any { + Proxy.injectCallback(obj) + return proxy(obj, args) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt index ace0992..9adb1ff 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt @@ -2,39 +2,16 @@ package cn.tursom.proxy import net.sf.cglib.proxy.MethodInterceptor import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Field import java.lang.reflect.Method -import java.util.* class ProxyInterceptor( - private val container: ProxyContainer = ListProxyContainer(), + val container: ProxyContainer = ListProxyContainer(), + // disable call super can save 20% time private val supportCallSuper: Boolean = true, ) : MethodInterceptor { - companion object { - val callSuper = ThreadLocal() - private val parameterTypes = arrayOf(Method::class.java, Array::class.java, MethodProxy::class.java) - private val parameterTypesField: Field = Method::class.java.getDeclaredField("parameterTypes").apply { - isAccessible = true - } - - @Suppress("UNCHECKED_CAST") - private fun getParameterTypes(method: Method): Array> { - return parameterTypesField[method] as Array> - } - - fun equalsMethod(method: Method, name: String?, parameterTypes: Array>?): Boolean { - return method.name == name && parameterTypes.contentEquals(getParameterTypes(method)) - } - - fun isOnProxyMethod(method: Method): Boolean { - //return callSuper.get() == true || equalsMethod(method, "onProxy", parameterTypes) - return callSuper.get() == true - } - } - override fun intercept(obj: Any, method: Method, args: Array, proxy: MethodProxy): Any? { - if (supportCallSuper && callSuper.get() == true) { - callSuper.remove() + if (supportCallSuper && Proxy.callSuper.get()) { + Proxy.callSuper.remove() return proxy.invokeSuper(obj, args) } @@ -45,4 +22,4 @@ class ProxyInterceptor( proxy.invokeSuper(obj, args) } } -} \ No newline at end of file +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt index 5142dae..ee08a89 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt @@ -9,12 +9,12 @@ import java.util.concurrent.ConcurrentHashMap interface ProxyMethod { @Throws(Throwable::class) - fun onProxy(obj: Any?, method: Method, args: Array, proxy: MethodProxy): ProxyResult<*> { + fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array, proxy: MethodProxy): ProxyResult<*> { val handlerCacheMap = getHandlerCacheMap(javaClass) val methodResult = handlerCacheMap[method] if (methodResult != null) { return if (methodResult.success) { - ProxyResult.of(methodResult.result(this, args)) + methodResult.result(this, args) } else { ProxyResult.failed() } @@ -34,7 +34,7 @@ interface ProxyMethod { if (reflectAsmMethod != null) { val (methodAccess, index) = reflectAsmMethod handlerCacheMap[method] = ProxyResult({ p, a -> - methodAccess.invoke(p, index, *a) + ProxyResult.of(methodAccess.invoke(p, index, *a)) }, true) return ProxyResult.of(methodAccess.invoke(this, index, *args)) } @@ -58,7 +58,7 @@ interface ProxyMethod { selfMethod = javaClass.getMethod(methodName, *method.parameterTypes) selfMethod.isAccessible = true handlerCacheMap[method] = ProxyResult({ p, a -> - selfMethod(p, *a) + ProxyResult.of(selfMethod(p, *a)) }, true) return ProxyResult.of(selfMethod(this, *args)) } catch (_: Exception) { @@ -70,11 +70,11 @@ interface ProxyMethod { companion object { private val handlerCacheMapMap: MutableMap< - Class, - MutableMap) -> Any?>>> = + Class, + MutableMap) -> ProxyResult<*>>>> = HashMap() - fun getHandlerCacheMap(type: Class): MutableMap) -> Any?>> { + fun getHandlerCacheMap(type: Class): MutableMap) -> ProxyResult<*>>> { var handlerCacheMap = handlerCacheMapMap[type] if (handlerCacheMap == null) synchronized(handlerCacheMapMap) { handlerCacheMap = handlerCacheMapMap[type] diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt index 3a57a6e..a8dfd4c 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt @@ -2,31 +2,34 @@ package cn.tursom.proxy import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method +import java.util.concurrent.ConcurrentHashMap -typealias ProxyMethodCacheFunction = (obj: Any?, method: Method, args: Array, proxy: MethodProxy) -> ProxyResult<*> +typealias ProxyMethodCacheFunction = (obj: Any, c: ProxyContainer, method: Method, args: Array, proxy: MethodProxy) -> ProxyResult<*> class ProxyMethodCache( private var lastModify: Long = 0, - private var function: ProxyMethodCacheFunction = failed, ) { companion object { - val failed: ProxyMethodCacheFunction = { _, _, _, _ -> ProxyResult.failed } + val failed: ProxyMethodCacheFunction = { _, _, _, _, _ -> ProxyResult.failed } } - fun update(lastModify: Long, function: ProxyMethodCacheFunction = this.function) { + private val functionMap = ConcurrentHashMap() + + fun update(lastModify: Long, proxy: MethodProxy, function: ProxyMethodCacheFunction = functionMap[proxy] ?: failed) { this.lastModify = lastModify - this.function = function + functionMap[proxy] = function } operator fun invoke( lastModify: Long, - obj: Any?, + obj: Any, + c: ProxyContainer, method: Method, args: Array, proxy: MethodProxy, ): ProxyResult<*>? = if (lastModify != this.lastModify) { null } else { - function(obj, method, args, proxy) + (functionMap[proxy] ?: failed)(obj, c, method, args, proxy) } } \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt index fddc51f..27fad62 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt @@ -5,7 +5,7 @@ import cn.tursom.core.uncheckedCast data class ProxyResult( val result: R, val success: Boolean = false, - val cache: Boolean = false, + val cache: Boolean = true, ) { companion object { val success: ProxyResult<*> = ProxyResult(null, true) diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt index fb89881..44f829a 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt @@ -12,10 +12,8 @@ import java.util.* object ProxyRunner { private val errMsgSearchList = arrayOf("%M", "%B", "%A") - private val forFirstProxyCacheKey = - ProxyContainer.contextEnv.newKey().withDefault { ProxyMethodCache() } - private val forEachProxyCacheKey = - ProxyContainer.contextEnv.newKey().withDefault { ProxyMethodCache() } + private val proxyMethodCacheKey = ProxyContainer.contextEnv.newKey() + .withDefault { ProxyMethodCache() } /** * will be call when proxy method invoke. @@ -23,10 +21,12 @@ object ProxyRunner { */ @Throws(Throwable::class) fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array, proxy: MethodProxy): ProxyResult<*> { - var handler = ProxyContainerHandlerCache.getHandler(proxy) - if (handler != null) { - return handler(obj, c, method, args, proxy) + val cache = c.context[proxyMethodCacheKey] + cache(c.lastModify, obj, c, method, args, proxy)?.let { + return it } + + var handler: ProxyMethodCacheFunction? = null for (annotation in method.annotations) when (annotation) { is ForEachProxy -> { handler = onForeachProxy(annotation) @@ -41,18 +41,17 @@ object ProxyRunner { //handler = ProxyContainerHandlerCache.callSuper handler = onForFirstProxy(ForFirstProxy.EMPTY) } - ProxyContainerHandlerCache.setHandler(proxy, handler) return handler(obj, c, method, args, proxy) } - private fun onForFirstProxy(forFirstProxy: ForFirstProxy): (Any, ProxyContainer, Method, Array, MethodProxy) -> ProxyResult<*> { - return { o: Any, c: ProxyContainer, m: Method, a: Array, p: MethodProxy -> - c.context[forFirstProxyCacheKey](c.lastModify, o, m, a, p) ?: 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() - }) + fun onForFirstProxy(forFirstProxy: ForFirstProxy): ProxyMethodCacheFunction { + val classes = when (forFirstProxy.value.size) { + 0 -> emptyList() + 1 -> listOf(forFirstProxy.value[0].java) + else -> forFirstProxy.value.asSequence().map { it.java }.toSet() + } + return { o, c, m: Method, a, p -> + onForFirstProxy(o, c, m, a, p, forFirstProxy, classes) } } @@ -65,12 +64,11 @@ object ProxyRunner { forFirstProxy: ForFirstProxy, classes: Collection>, ): ProxyResult<*> { - val cache = container.context[forFirstProxyCacheKey] val result = container.forFirstProxy { p -> if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(p) }) { - val result = p.onProxy(obj, method, args, proxy) + val result = p.onProxy(obj, container, method, args, proxy) if (forFirstProxy.cache && result.success && result.cache) { - cache.update(container.lastModify, p::onProxy) + container.context[proxyMethodCacheKey].update(container.lastModify, proxy, p::onProxy) } return@forFirstProxy result } else { @@ -103,34 +101,48 @@ object ProxyRunner { errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList) val exceptionConstructor = forFirstProxy.errClass.java.getConstructor(String::class.java) if (forFirstProxy.cache) { - cache.update(container.lastModify) { _, _, _, _ -> + container.context[proxyMethodCacheKey].update(container.lastModify, proxy) { _, _, _, _, _ -> throw exceptionConstructor.newInstance(errMsg) } } throw exceptionConstructor.newInstance(errMsg) } if (forFirstProxy.cache) { - cache.update(container.lastModify) + container.context[proxyMethodCacheKey].update(container.lastModify, proxy) } return ProxyResult.failed } - private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) { + 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() - }) + }, forEachProxy.cache) + private val emptyProxyList = ArrayList() private fun onForeachProxy( classes: Collection>, - ): (Any, ProxyContainer, Method, Array, MethodProxy) -> ProxyResult { - return (label@{ o: Any, c: ProxyContainer, m: Method, a: Array, proxy1: MethodProxy -> - c.forEachProxy { p -> - if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) { - p.onProxy(o, m, a, proxy1) + cache: Boolean, + ): ProxyMethodCacheFunction = { o, c, m, a, proxy -> + val proxyList = if (cache) ArrayList() else emptyProxyList + c.forEachProxy { p -> + if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) { + val result = p.onProxy(o, c, m, a, proxy) + if (cache && result.success) { + proxyList.add(p) } } - ProxyResult.failed() - }) + } + if (cache) { + c.context[proxyMethodCacheKey].update(c.lastModify, proxy, onCachedForeachProxy((proxyList))) + } + ProxyResult.failed() + } + + private fun onCachedForeachProxy(proxyList: List): ProxyMethodCacheFunction = { o, c, m, a, proxy -> + proxyList.forEach { p -> + p.onProxy(o, c, m, a, proxy) + } + ProxyResult.failed() } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForEachProxy.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForEachProxy.kt index 0546220..13ddb01 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForEachProxy.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForEachProxy.kt @@ -4,4 +4,8 @@ import kotlin.reflect.KClass @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) @Retention(AnnotationRetention.RUNTIME) -annotation class ForEachProxy(vararg val value: KClass<*> = [], val name: String = "") \ No newline at end of file +annotation class ForEachProxy( + vararg val value: KClass<*> = [], + val name: String = "", + val cache: Boolean = true, +) \ No newline at end of file diff --git a/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt b/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt index f5ce338..236350d 100644 --- a/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt +++ b/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt @@ -1,6 +1,8 @@ package cn.tursom.proxy import org.junit.Test +import org.objectweb.asm.ClassWriter +import java.io.File class Example { open class TestClass protected constructor() { @@ -12,14 +14,54 @@ class Example { private val t: TestClass, ) : ProxyMethod { fun getA(): Int { - ProxyInterceptor.callSuper.set(true) + Proxy.callSuper.set(true) return t.a + 1 } } + @Test + fun getClass() { + val writer = ClassWriter(0) + val enhancer = Proxy.newEnhancer(TestClass::class.java) + val clazz = enhancer.createClass() + CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor())) + val instance = clazz.newInstance() + enhancer.generateClass(writer) + File("TestClass.class").writeBytes(writer.toByteArray()) + } @Test fun test() { + //val enhancer = Enhancer() + //enhancer.setSuperclass(TestClass::class.java) + //enhancer.setCallback(ProxyDispatcher) + //val t = enhancer.create() as TestClass + //val enhancer = Enhancer() + //enhancer.setSuperclass(TestClass::class.java) + //enhancer.setCallback(ProxyRefDispatcher { + // println("on Dispatcher") + // ProxyInterceptor() + //}) + // + //val t = enhancer.create() as TestClass + //val writer = ClassWriter(0) + //enhancer.generateClass(writer) + //File("TestClass_ProxyRefDispatcher.class").writeBytes(writer.toByteArray()) + val (t, container) = Proxy.get() + //val t = Proxy.getCachedTarget(TestClass::class.java).newInstance() + //val container = Proxy.injectCallback(t) + //container as MutableProxyContainer + container.addProxy(GetA(t)) + + println(t.javaClass) + repeat(10) { + t.a = t.a + println(t.a) + } + } + + @Test + fun benchmark() { val (t, container) = Proxy.get() container.addProxy(GetA(t)) diff --git a/ts-core/ts-reflectasm/src/main/kotlin/cn/tursom/reflect/asm/ReflectAsmUtils.kt b/ts-core/ts-reflectasm/src/main/kotlin/cn/tursom/reflect/asm/ReflectAsmUtils.kt index ff0818b..abb2740 100644 --- a/ts-core/ts-reflectasm/src/main/kotlin/cn/tursom/reflect/asm/ReflectAsmUtils.kt +++ b/ts-core/ts-reflectasm/src/main/kotlin/cn/tursom/reflect/asm/ReflectAsmUtils.kt @@ -91,41 +91,54 @@ object ReflectAsmUtils { returnType = method.returnType, ) - inline fun getMethod0(methodName: String): (T.() -> R)? { - val (methodAccess, index) = getMethod(T::class.java, methodName, returnType = R::class.java) + inline fun getMethod0( + methodName: String, + type: Class = T::class.java, + returnType: Class = R::class.java, + ): (T.() -> R)? { + val (methodAccess, index) = getMethod(type, methodName, returnType = returnType) ?: return null return { methodAccess.invoke(this, index) as R } } - inline fun getMethod1(methodName: String): (T.(A1) -> R)? { - val (methodAccess, index) = getMethod(T::class.java, methodName, A1::class.java, returnType = R::class.java) + inline fun getMethod1( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + returnType: Class = R::class.java, + ): (T.(A1) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, returnType = returnType) ?: return null return { a1 -> methodAccess.invoke(this, index, a1) as R } } - inline fun 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) + inline fun getMethod2( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + returnType: Class = R::class.java, + ): (T.(A1, A2) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, returnType = returnType) ?: return null return { a1, a2 -> methodAccess.invoke(this, index, a1, a2) as R } } - inline fun 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) + inline fun getMethod3( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + returnType: Class = R::class.java, + ): (T.(A1, A2, A3) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, returnType = returnType) ?: return null return { a1, a2, a3 -> methodAccess.invoke(this, index, a1, a2, a3) as R @@ -133,14 +146,16 @@ object ReflectAsmUtils { } inline fun - 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) + getMethod4( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + returnType: Class = R::class.java, + ): (T.(A1, A2, A3, A4) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, returnType = returnType) ?: return null return { a1, a2, a3, a4 -> methodAccess.invoke(this, index, a1, a2, a3, a4) as R @@ -148,15 +163,17 @@ object ReflectAsmUtils { } inline fun - 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) + getMethod5( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + ta5: Class = A5::class.java, + returnType: Class = R::class.java, + ): (T.(A1, A2, A3, A4, A5) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, returnType = returnType) ?: return null return { a1, a2, a3, a4, a5 -> methodAccess.invoke(this, index, a1, a2, a3, a4, a5) as R @@ -164,19 +181,126 @@ object ReflectAsmUtils { } inline fun - 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) + getMethod6( + methodName: String, + type: Class = T::class.java, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + ta5: Class = A5::class.java, + ta6: Class = A6::class.java, + returnType: Class = R::class.java, + ): (T.(A1, A2, A3, A4, A5, A6) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, ta6, returnType = returnType) ?: return null return { a1, a2, a3, a4, a5, a6 -> methodAccess.invoke(this, index, a1, a2, a3, a4, a5, a6) as R } } + + inline fun getStaticMethod0( + type: Class<*>, + methodName: String, + returnType: Class = R::class.java, + ): (() -> R)? { + val (methodAccess, index) = getMethod(type, methodName, returnType = returnType) + ?: return null + return { + methodAccess.invoke(null, index) as R + } + } + + inline fun getStaticMethod1( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + returnType: Class = R::class.java, + ): ((A1) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, returnType = returnType) + ?: return null + return { a1 -> + methodAccess.invoke(null, index, a1) as R + } + } + + inline fun getStaticMethod2( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + returnType: Class = R::class.java, + ): ((A1, A2) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, returnType = returnType) + ?: return null + return { a1, a2 -> + methodAccess.invoke(null, index, a1, a2) as R + } + } + + inline fun getStaticMethod3( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + returnType: Class = R::class.java, + ): ((A1, A2, A3) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, returnType = returnType) + ?: return null + return { a1, a2, a3 -> + methodAccess.invoke(null, index, a1, a2, a3) as R + } + } + + inline fun getStaticMethod4( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + returnType: Class = R::class.java, + ): ((A1, A2, A3, A4) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, returnType = returnType) + ?: return null + return { a1, a2, a3, a4 -> + methodAccess.invoke(null, index, a1, a2, a3, a4) as R + } + } + + inline fun getStaticMethod5( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + ta5: Class = A5::class.java, + returnType: Class = R::class.java, + ): ((A1, A2, A3, A4, A5) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, returnType = returnType) + ?: return null + return { a1, a2, a3, a4, a5 -> + methodAccess.invoke(null, index, a1, a2, a3, a4, a5) as R + } + } + + inline fun getStaticMethod6( + type: Class<*>, + methodName: String, + ta1: Class = A1::class.java, + ta2: Class = A2::class.java, + ta3: Class = A3::class.java, + ta4: Class = A4::class.java, + ta5: Class = A5::class.java, + ta6: Class = A6::class.java, + returnType: Class = R::class.java, + ): ((A1, A2, A3, A4, A5, A6) -> R)? { + val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, ta6, returnType = returnType) + ?: return null + return { a1, a2, a3, a4, a5, a6 -> + methodAccess.invoke(null, index, a1, a2, a3, a4, a5, a6) as R + } + } } diff --git a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlDialect.kt b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlDialect.kt index aef1be0..fa87e7a 100644 --- a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlDialect.kt +++ b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlDialect.kt @@ -13,7 +13,7 @@ class ExtSqlDialect( ) : 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] + val (proxyFormatter, container) = Proxy.get(formatter.javaClass) { InstantAllocator(it) } run { val extSqlFormatter = ExtSqlFormatter(formatter) extSqlFormatter.registerVisitor(DirectSqlExpression.visitor)