diff --git a/build.gradle.kts b/build.gradle.kts index c5bb37a..a037f11 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.6.20" + kotlin("jvm") version "1.8.0" `maven-publish` id("ts-gradle") } @@ -10,12 +10,7 @@ allprojects { group = "cn.tursom" version = "1.0-SNAPSHOT" - repositories { - //mavenCentral() - maven { - url = uri("https://nvm.tursom.cn/repository/maven-public/") - } - } + useTursomRepositories() tasks.withType { tasks.withType().configureEach { @@ -23,9 +18,7 @@ allprojects { kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" } - if (project.gradle.startParameter.taskNames.firstOrNull { taskName -> - taskName.endsWith(":test") - } == null) { + if (!isTestRunning) { tasks.withType { enabled = false } @@ -37,6 +30,8 @@ allprojects { kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" //kotlinOptions.useIR = true } + + autoConfigPublish() } @@ -50,7 +45,3 @@ dependencies { artifacts { archives(tasks["kotlinSourcesJar"]) } - -publishing { - publish(this) -} diff --git a/gradle.properties b/gradle.properties index 9bb1cb2..c436ebe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,3 +19,6 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official + +project.groupId=cn.tursom +project.version=1.0-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da9702f..070cb70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ts-core/build.gradle.kts b/ts-core/build.gradle.kts index 4b6f30e..8bb8848 100644 --- a/ts-core/build.gradle.kts +++ b/ts-core/build.gradle.kts @@ -15,6 +15,4 @@ dependencies { testApi(group = "junit", name = "junit", version = "4.13.2") } - - - +autoConfigPublish() diff --git a/ts-core/src/main/kotlin/cn/tursom/core/context/ArrayContextEnv.kt b/ts-core/src/main/kotlin/cn/tursom/core/context/ArrayContextEnv.kt index 140a26a..d776069 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/context/ArrayContextEnv.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/context/ArrayContextEnv.kt @@ -4,7 +4,7 @@ import cn.tursom.core.uncheckedCast import java.util.concurrent.atomic.AtomicInteger class ArrayContextEnv : ContextEnv { - val envId = ContextEnv.newEnvId() + override val envId = ContextEnv.newEnvId() private val idGenerator = AtomicInteger() private val emptyContext = EmptyArrayContext(envId, idGenerator) diff --git a/ts-core/src/main/kotlin/cn/tursom/core/context/ContextEnv.kt b/ts-core/src/main/kotlin/cn/tursom/core/context/ContextEnv.kt index c273518..c39601b 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/context/ContextEnv.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/context/ContextEnv.kt @@ -8,6 +8,8 @@ interface ContextEnv { fun newEnvId() = contextEnvIdGenerator.incrementAndGet() } + val envId: Int + fun emptyContext(): Context = newContext() fun newContext(): Context fun newKey(): ContextKey diff --git a/ts-core/src/main/kotlin/cn/tursom/core/context/HashMapContextEnv.kt b/ts-core/src/main/kotlin/cn/tursom/core/context/HashMapContextEnv.kt index 3965585..485561e 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/context/HashMapContextEnv.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/context/HashMapContextEnv.kt @@ -4,7 +4,7 @@ import cn.tursom.core.uncheckedCast import java.util.concurrent.atomic.AtomicInteger class HashMapContextEnv : ContextEnv { - val envId = ContextEnv.newEnvId() + override val envId = ContextEnv.newEnvId() private val idGenerator = AtomicInteger() override fun newContext(): Context = HashMapContext(envId) diff --git a/ts-core/src/test/kotlin/main.kt b/ts-core/src/test/kotlin/main.kt index cac13fb..bec8125 100644 --- a/ts-core/src/test/kotlin/main.kt +++ b/ts-core/src/test/kotlin/main.kt @@ -1,12 +1,33 @@ import java.math.BigInteger -fun main() { - val two = BigInteger.valueOf(2) - val three = BigInteger.valueOf(3) - val ten = BigInteger.TEN - var i = BigInteger.ONE - repeat(1000) { - i *= two - print("${i / ten / ten / ten % ten}") +enum class Status(val id: Int) : (Int) -> Int { + S1(1), S2(2), S3(3); + + override fun invoke(i: Int): Int { + return 0 } + + infix fun or(status: Status) = status.id or id + infix fun or(status: Int) = id or status +} + +infix fun Int.or(status: Status) = this or status.id + +inline fun Any.instanceOf() = this is T + +fun main() { + println(1.instanceOf()) + println(1L.instanceOf()) + println(1f.instanceOf()) + + //var i1 = 1 or Status.S1 + // + //val two = BigInteger.valueOf(2) + //val three = BigInteger.valueOf(3) + //val ten = BigInteger.TEN + //var i = BigInteger.ONE + //repeat(1000) { + // i *= two + // print("${i / ten / ten / ten % ten}") + //} } \ No newline at end of file diff --git a/ts-core/ts-coroutine/src/test/kotlin/main.kt b/ts-core/ts-coroutine/src/test/kotlin/main.kt new file mode 100644 index 0000000..544b075 --- /dev/null +++ b/ts-core/ts-coroutine/src/test/kotlin/main.kt @@ -0,0 +1,8 @@ +import kotlinx.coroutines.delay + +tailrec fun pow(i: Int, n: Int = 1): Int = if (i <= 0) n else pow(i - 1, i * n) + +suspend fun main() { + delay(pow(10).toLong()) + println("finished") +} diff --git a/ts-core/ts-curry/src/main/kotlin/cn/tursom/core/curry/main.kt b/ts-core/ts-curry/src/main/kotlin/cn/tursom/core/curry/main.kt new file mode 100644 index 0000000..ff8ed19 --- /dev/null +++ b/ts-core/ts-curry/src/main/kotlin/cn/tursom/core/curry/main.kt @@ -0,0 +1,16 @@ +package cn.tursom.core.curry + +import cn.tursom.core.allMemberPropertiesSequence +import java.util.concurrent.ConcurrentHashMap + +fun example(f: (Int) -> (Int) -> (Int) -> Int) { + f(1)(2)(3) + + f(1, 2, 3) +} + +fun example2(f: (Int, Int, Int) -> Int) { + f(1, 2, 3) + + f(1, 2)(3) +} diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt index 00d1f0c..8cd4d56 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt @@ -8,10 +8,12 @@ import kotlin.reflect.KProperty * 如果你还需要对这个属性进行加锁,你就可以在后方加一个 .locked 即可 * 如果还需要用指定的锁,在后面再加一个 (lock) 就玩成了 * 使用例: + * ``` * class XXXImpl: XXX, FieldChangeListener by FieldChangeListenerImpl() { * val lock = ReentrantLock() * val field by listened(0).locker(lock) * } + * ``` */ interface DelegatedField { /** diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/main.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/main.kt new file mode 100644 index 0000000..8e37d30 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/main.kt @@ -0,0 +1,49 @@ +package cn.tursom.core.delegation.observer + +import cn.tursom.core.delegation.expirable +import cn.tursom.core.delegation.filter +import cn.tursom.core.delegation.notNull +import java.lang.Thread.sleep + +class A { + @OptIn(Listenable::class) + var field by listenable(0) + .filter { _, new -> + new >= 0 + } + .expirable(100) + .notNull { + throw IllegalAccessError() + } + + @OptIn(Listenable::class) + var canServer by listenable(true) + + @OptIn(Listenable::class) + var count: Int by listenable(0) +} + +fun f(obj: A) { + obj::field.listen { old: Int?, new: Int? -> + println("old: $old, new: $new") + } + + obj::canServer.listen { old, new -> + println(new) + } + + obj::count.listen { old, new -> + + } +} + +fun main() { + val a = A() + f(a) + + a.field = 1 + println(a.field) + + sleep(1000) + println(a.field) +} diff --git a/ts-core/ts-proxy/a b/ts-core/ts-proxy/a deleted file mode 100644 index e69de29..0000000 diff --git a/ts-core/ts-proxy/build.gradle.kts b/ts-core/ts-proxy/build.gradle.kts index 64b88ec..23fa240 100644 --- a/ts-core/ts-proxy/build.gradle.kts +++ b/ts-core/ts-proxy/build.gradle.kts @@ -11,7 +11,7 @@ dependencies { api(project(":ts-core")) api(project(":ts-core:ts-reflectasm")) api(group = "cglib", name = "cglib", version = "3.3.0") - implementation(group = "net.bytebuddy", name = "byte-buddy", version = "1.12.22") + //implementation(group = "net.bytebuddy", name = "byte-buddy", version = "1.12.22") implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.8.1") testApi(group = "junit", name = "junit", version = "4.13.2") } diff --git a/ts-core/ts-proxy/src/main/java/cn/tursom/proxy/function/JavaReflectASMProxyMethodInvoker.java b/ts-core/ts-proxy/src/main/java/cn/tursom/proxy/function/JavaReflectASMProxyMethodInvoker.java new file mode 100644 index 0000000..28dc7c3 --- /dev/null +++ b/ts-core/ts-proxy/src/main/java/cn/tursom/proxy/function/JavaReflectASMProxyMethodInvoker.java @@ -0,0 +1,34 @@ +package cn.tursom.proxy.function; + +import cn.tursom.proxy.container.ProxyContainer; +import cn.tursom.proxy.container.ProxyMethodCacheFunction; +import com.esotericsoftware.reflectasm.MethodAccess; +import net.sf.cglib.proxy.MethodProxy; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Method; + +public class JavaReflectASMProxyMethodInvoker implements ProxyMethodCacheFunction { + private final Object self; + private final MethodAccess methodAccess; + private final int index; + + public JavaReflectASMProxyMethodInvoker(Object self, MethodAccess methodAccess, int index) { + this.self = self; + this.methodAccess = methodAccess; + this.index = index; + } + + @Nullable + @Override + public Object invoke( + @Nullable Object obj, + @NotNull ProxyContainer c, + @Nullable Method method, + @Nullable Object[] args, + @Nullable MethodProxy proxy + ) { + return methodAccess.invoke(self, index, args); + } +} 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 30ab0f0..b918dc1 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 @@ -7,6 +7,7 @@ import cn.tursom.proxy.container.ListProxyContainer import cn.tursom.proxy.container.MutableProxyContainer import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.function.ProxyMethod +import cn.tursom.proxy.interceptor.CachedMethodInterceptor import cn.tursom.proxy.interceptor.LocalCachedProxyInterceptor import cn.tursom.proxy.interceptor.ProxyInterceptor import cn.tursom.reflect.final @@ -23,14 +24,18 @@ object Proxy { it.final = false } - fun getContainer(obj: Any): ProxyContainer? { - if (obj !is Factory) return null + fun getContainer(obj: Factory): ProxyContainer? { val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null return interceptor.container } + fun getMutableContainer(obj: Factory): MutableProxyContainer? { + val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null + return interceptor.container as? MutableProxyContainer + } + fun addProxy(obj: Any, proxy: ProxyMethod): Boolean { - val container = getContainer(obj) as? MutableProxyContainer ?: return false + val container = getContainer(obj as Factory) as? MutableProxyContainer ?: return false container.addProxy(proxy) return true } @@ -48,7 +53,7 @@ object Proxy { container.target = obj container.ctx[directAccessorKey] = directAccessor - injectCallback(obj as Factory, container, directAccessor) + injectCallback(obj as Factory, container, directAccessor as Factory) return obj to container } @@ -137,6 +142,7 @@ object Proxy { fun newEnhancer(clazz: Class, vararg interfaces: Class<*>): Enhancer { val enhancer = Enhancer() + enhancer.setSuperclass(clazz) if (interfaces.isNotEmpty()) { enhancer.setInterfaces(interfaces) @@ -151,15 +157,17 @@ object Proxy { } @JvmOverloads - fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer(), target: Any = obj): ProxyContainer { - obj as Factory + fun injectCallback( + obj: Factory, + container: ProxyContainer = defaultContainer(), + target: Factory = obj, + ): ProxyContainer { if (obj.getCallback(0) != null && obj.getCallback(0) is ProxyInterceptor) { return (obj.getCallback(0) as ProxyInterceptor).container } - val nonProxyClasses: MutableSet> = HashSet(listOf(Any::class.java)) repeat(obj.callbacks.size) { - obj.setCallback(it, LocalCachedProxyInterceptor(container, nonProxyClasses, target)) + obj.setCallback(it, LocalCachedProxyInterceptor(container, target)) } return container } @@ -170,27 +178,30 @@ object Proxy { fun getSuperCaller( obj: T, - ): T = getContainer(obj)?.ctx?.get(directAccessorKey).uncheckedCast() + ): T = getContainer(obj as Factory)?.ctx?.get(directAccessorKey).uncheckedCast() - fun addNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { - if (target !is Factory || - target.getCallback(0) == null || - target.getCallback(0) !is ProxyInterceptor - ) { - throw IllegalArgumentException() - } - - return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.add(nonProxyClass) + fun addNonProxyClass(target: Factory, nonProxyClass: Class<*>): Boolean { + val container = getMutableContainer(target) ?: throw IllegalArgumentException() + return container.nonProxyClasses.add(nonProxyClass) } - fun removeNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { - if (target !is Factory || - target.getCallback(0) == null || - target.getCallback(0) !is ProxyInterceptor - ) { - throw IllegalArgumentException() - } + fun removeNonProxyClass(target: Factory, nonProxyClass: Class<*>): Boolean { + val container = getMutableContainer(target) ?: throw IllegalArgumentException() + return container.nonProxyClasses.remove(nonProxyClass) + } - return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.remove(nonProxyClass) + fun clearCallbackCache(target: Factory, container: ProxyContainer) { + target.callbacks.forEachIndexed { index, callback -> + if (callback == null) { + target.setCallback(index, LocalCachedProxyInterceptor(container, target)) + return@forEachIndexed + } + + if (callback !is CachedMethodInterceptor) { + return@forEachIndexed + } + + callback.clearCache() + } } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt index 5707c58..3897828 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt @@ -1,19 +1,22 @@ package cn.tursom.proxy.container import cn.tursom.core.context.Context +import cn.tursom.proxy.Proxy import cn.tursom.proxy.function.ProxyMethod -import cn.tursom.proxy.util.CglibUtil -import net.sf.cglib.proxy.MethodProxy +import net.sf.cglib.proxy.Factory class ListProxyContainer( private val proxyList: MutableCollection = ArrayList(), + override val nonProxyClasses: MutableSet> = HashSet(listOf(Any::class.java)), ) : MutableProxyContainer { override lateinit var target: Any override val ctx: Context = ProxyContainer.ctxEnv.newContext() private fun clearCache() { ctx[ProxyMethodCache.ctxKey].clear() + + Proxy.clearCallbackCache(target as Factory, this) } override fun addProxy(proxy: Any) { diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt index 2c87c43..9e08683 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt @@ -2,6 +2,7 @@ package cn.tursom.proxy.container interface MutableProxyContainer : ProxyContainer { override var target: Any + override val nonProxyClasses: MutableSet> fun addProxy(proxy: Any) fun addAllProxy(proxy: Collection?) diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt index 75a8641..8cbe0bf 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt @@ -11,4 +11,5 @@ interface ProxyContainer : Iterable { // to impl, use override val context: Context = ProxyContainer.contextEnv.newContext() val ctx: Context val target: Any + val nonProxyClasses: Set> } \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt index ced0d22..2436748 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt @@ -1,7 +1,9 @@ package cn.tursom.proxy.container +import cn.tursom.proxy.function.ProxyMethod import cn.tursom.proxy.util.IntMap import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method class ProxyMethodCache { companion object { @@ -18,9 +20,22 @@ class ProxyMethodCache { } } - fun update(proxy: MethodProxy, function: ProxyMethodCacheFunction) { + fun update( + obj: Any, + container: ProxyContainer, + method: Method, + proxy: MethodProxy, + function: ProxyMethodCacheFunction, + ) { + var handler = function + container.forEach { + if (it !is ProxyMethod) return@forEach + + handler = it.onProxyHandlerCacheUpdate(handler, obj, container, method, proxy) + } + synchronized(this) { - functionMap[proxy.superIndex] = function + functionMap[proxy.superIndex] = handler } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt index e5c9fbd..e3ff169 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt @@ -1,13 +1,14 @@ package cn.tursom.proxy.container -import cn.tursom.proxy.container.ProxyContainer import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method -fun interface ProxyMethodCacheFunction : ( - Any?, - ProxyContainer, - Method?, - Array?, - MethodProxy?, -) -> Any? +fun interface ProxyMethodCacheFunction { + operator fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt index 1e56739..4b25c6c 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt @@ -15,11 +15,10 @@ class CachedOnForEachProxyImpl( a: Array?, proxy: MethodProxy?, ): Any? { - proxy!! - proxyList.forEach { p -> p(o, c, m, a, proxy) } - return proxy.invokeSuper(o, a) + + return proxy!!.invokeSuper(o, a) } } \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt index db4181e..333a0b3 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt @@ -2,10 +2,22 @@ package cn.tursom.proxy.function import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyMethodCacheFunction +import cn.tursom.reflect.asm.ReflectAsmUtils import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method object CallSuperProxyMethodCacheFunction : ProxyMethodCacheFunction { + operator fun get(obj: Any, method: Method): ProxyMethodCacheFunction { + val (methodAccess, index) = ReflectAsmUtils.getMethodByRegex( + obj.javaClass, + "CGLIB\\\$${method.name}\\\$.*".toRegex(), + *method.parameterTypes, + method.returnType, + ) ?: return CallSuperProxyMethodCacheFunction + + return ReflectASMProxyMethodInvoker(obj, methodAccess, index).toJava() + } + override fun invoke( obj: Any?, c: ProxyContainer, diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JvmReflectProxyMethodInvoker.kt similarity index 76% rename from ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt rename to ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JvmReflectProxyMethodInvoker.kt index 1ae879c..ab0e8a6 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JvmReflectProxyMethodInvoker.kt @@ -4,21 +4,20 @@ import cn.tursom.proxy.annotation.ForEachProxy import cn.tursom.proxy.annotation.ForFirstProxy import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyMethodCacheFunction +import cn.tursom.reflect.asm.ReflectAsmInvoker import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method -internal class JavaReflectProxyMethodInvoker( +internal class JvmReflectProxyMethodInvoker( private val self: Any, private val method: Method, ) : ProxyMethodCacheFunction { companion object { - private val fastInvoker: Method.(Any?, Array?) -> Any? = Method::invoke - operator fun get( proxy: Any, method: Method, - ): JavaReflectProxyMethodInvoker? { - var invoker: JavaReflectProxyMethodInvoker? = null + ): JvmReflectProxyMethodInvoker? { + var invoker: JvmReflectProxyMethodInvoker? = null val selfMethod: Method try { @@ -39,9 +38,7 @@ internal class JavaReflectProxyMethodInvoker( selfMethod = proxy.javaClass.getMethod(methodName, *method.parameterTypes) selfMethod.isAccessible = true - invoker = JavaReflectProxyMethodInvoker(proxy, method) - - //handlerCacheMap[method] = ProxyResult(invoker, true) + invoker = JvmReflectProxyMethodInvoker(proxy, method) } catch (_: Exception) { } @@ -56,6 +53,6 @@ internal class JavaReflectProxyMethodInvoker( args: Array?, proxy: MethodProxy?, ): Any? { - return fastInvoker(this.method, self, args) + return ReflectAsmInvoker.invoke(this.method, self, args) } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt index 7e9958c..0dd3a72 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt @@ -30,7 +30,6 @@ class OnForEachProxyImpl( proxy: MethodProxy?, ): Any? { m!! - proxy!! val proxyList = if (cache) ArrayList() else emptyProxyList c.forEach { p -> @@ -42,9 +41,13 @@ class OnForEachProxyImpl( } } } + + proxy!! + if (cache) { c.ctx[ProxyMethodCache.ctxKey].update( - proxy, CachedOnForEachProxyImpl(proxyList) + o!!, c, m, proxy, + CachedOnForEachProxyImpl(proxyList), ) } return proxy.invokeSuper(o, a) diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt index 4f1b716..928919e 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt @@ -32,6 +32,7 @@ class OnForFirstProxyImpl( ): Any? { method!! proxy!! + obj!! container.forEach { p -> if (classes.isNotEmpty() && classes.none { c: Class<*> -> c.isInstance(p) }) { @@ -40,7 +41,7 @@ class OnForFirstProxyImpl( val handler = ProxyMethod.getHandler(p, method) ?: return@forEach if (ffpAnnotation.cache) { - container.ctx[ProxyMethodCache.ctxKey].update(proxy, handler) + container.ctx[ProxyMethodCache.ctxKey].update(obj, container, method, proxy, handler) } return handler(obj, container, method, args, proxy) } @@ -68,15 +69,15 @@ class OnForFirstProxyImpl( val exceptionConstructor = ffpAnnotation.errClass.java.getConstructor(String::class.java) if (ffpAnnotation.cache) { container.ctx[ProxyMethodCache.ctxKey].update( - proxy, ExceptionProxyMethodCacheFunctionImpl(exceptionConstructor, errMsg) + obj, container, method, proxy, ExceptionProxyMethodCacheFunctionImpl(exceptionConstructor, errMsg) ) } throw exceptionConstructor.newInstance(errMsg) } if (ffpAnnotation.cache) { container.ctx[ProxyMethodCache.ctxKey].update( - proxy, - CallSuperProxyMethodCacheFunction, + obj, container, method, proxy, + CallSuperProxyMethodCacheFunction[obj, method] ) } return proxy.invokeSuper(obj, args) diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt index de873bd..22b6f26 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt @@ -14,6 +14,13 @@ interface ProxyMethod { // NO-OP } + fun onGet(f: ProxyMethodCacheFunction, method: Method): ProxyMethodCacheFunction = f + + /** + * disabled on default. + * + * override onCached to enable it + */ fun onProxyInvoke( o: Any?, c: ProxyContainer, @@ -25,12 +32,25 @@ interface ProxyMethod { return next(o, c, m, a, proxy) } + /** + * 当有缓存更新时被调用 + * + * 你可以以此替换缓存方法 + */ + fun onProxyHandlerCacheUpdate( + f: ProxyMethodCacheFunction, + obj: Any, + container: ProxyContainer, + method: Method, + proxy: MethodProxy, + ) = f + companion object { fun getHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { var handler = getReflectHandler(proxy, method) ?: return null if (proxy is ProxyMethod) { - handler = ProxyMethodInvoker(proxy, handler) + handler = proxy.onGet(handler, method) } return handler @@ -39,10 +59,10 @@ interface ProxyMethod { private fun getReflectHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { val reflectAsmHandler = ReflectASMProxyMethodInvoker[proxy, method] if (reflectAsmHandler != null) { - return reflectAsmHandler + return reflectAsmHandler.toJava() } - val javaReflectHandler = JavaReflectProxyMethodInvoker[proxy, method] + val javaReflectHandler = JvmReflectProxyMethodInvoker[proxy, method] if (javaReflectHandler != null) { return javaReflectHandler } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt index a7d202b..98aac64 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt @@ -2,6 +2,7 @@ package cn.tursom.proxy.function import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyMethodCacheFunction +import cn.tursom.reflect.asm.ReflectAsmInvoker import cn.tursom.reflect.asm.ReflectAsmUtils import com.esotericsoftware.reflectasm.MethodAccess import net.sf.cglib.proxy.MethodProxy @@ -13,19 +14,35 @@ internal class ReflectASMProxyMethodInvoker( private val index: Int, ) : ProxyMethodCacheFunction { companion object { - private val fastInvoker: MethodAccess.(Any, Int, Array?) -> Any? = MethodAccess::invoke - operator fun get( proxy: Any, method: Method, ): ReflectASMProxyMethodInvoker? { val reflectAsmMethod = try { - ReflectAsmUtils.getMethod( + val methodParamTypes = method.parameterTypes + val matchedMethods = ReflectAsmUtils.getMethodSequence( proxy.javaClass, method.name, - paramTypes = method.parameterTypes, + paramTypes = methodParamTypes, returnType = method.returnType, - ) + ).toList() + when { + matchedMethods.isEmpty() -> null + + matchedMethods.size == 1 -> matchedMethods.first() + + else -> matchedMethods.minBy { (methodAccess, methodIndex) -> + var parameterIndex = 0 + methodAccess.parameterTypes[methodIndex].sumOf { parameterType -> + if (methodParamTypes[parameterIndex++] != parameterType) { + 0L + } else { + 1L + } + } + } + + } } catch (e: Exception) { e.printStackTrace() null @@ -36,6 +53,8 @@ internal class ReflectASMProxyMethodInvoker( } } + fun toJava() = JavaReflectASMProxyMethodInvoker(self, methodAccess, index) + override fun invoke( obj: Any?, c: ProxyContainer, @@ -43,6 +62,6 @@ internal class ReflectASMProxyMethodInvoker( args: Array?, proxy: MethodProxy?, ): Any? { - return fastInvoker(methodAccess, self, index, args) + return ReflectAsmInvoker.invoke(methodAccess, self, index, args) } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/CachedMethodInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/CachedMethodInterceptor.kt new file mode 100644 index 0000000..3a88874 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/CachedMethodInterceptor.kt @@ -0,0 +1,7 @@ +package cn.tursom.proxy.interceptor + +import net.sf.cglib.proxy.MethodInterceptor + +interface CachedMethodInterceptor : MethodInterceptor { + fun clearCache() +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt index 5808e38..59c6389 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt @@ -1,5 +1,6 @@ package cn.tursom.proxy.interceptor +import cn.tursom.reflect.asm.ReflectAsmInvoker import cn.tursom.reflect.asm.ReflectAsmUtils import com.esotericsoftware.reflectasm.MethodAccess import net.sf.cglib.proxy.InvocationHandler @@ -8,10 +9,6 @@ import java.lang.reflect.Method class LocalCachedNoProxyInvocationHandler( val proxy: Any, ) : InvocationHandler { - companion object { - private val fastInvoker: MethodAccess.(Any, Int, Array?) -> Any? = MethodAccess::invoke - } - private var handler: (method: Method?, args: Array?) -> Any? = DefaultHandler() override fun invoke(ignore: Any, method: Method?, args: Array?): Any? { @@ -29,7 +26,7 @@ class LocalCachedNoProxyInvocationHandler( method.returnType, )!! handler = MethodAccessHandler(methodAccess, index) - return fastInvoker(methodAccess, proxy, index, args) + return ReflectAsmInvoker.invoke(methodAccess, proxy, index, args) } } @@ -37,6 +34,7 @@ class LocalCachedNoProxyInvocationHandler( private val methodAccess: MethodAccess, private val index: Int, ) : (Method?, Array?) -> Any? { - override fun invoke(method: Method?, args: Array?) = fastInvoker(methodAccess, proxy, index, args) + override fun invoke(method: Method?, args: Array?) = + ReflectAsmInvoker.invoke(methodAccess, proxy, index, args) } } \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt index c29d359..d808ccf 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt @@ -3,29 +3,36 @@ package cn.tursom.proxy.interceptor import cn.tursom.proxy.container.ProxyContainer import cn.tursom.proxy.container.ProxyMethodCache import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.Factory import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method class LocalCachedProxyInterceptor( container: ProxyContainer, - nonProxyClasses: MutableSet>, - val target: Any, -) : ProxyInterceptor(container, nonProxyClasses) { + val target: Factory, +) : ProxyInterceptor(container), CachedMethodInterceptor { private var cache: ProxyMethodCacheFunction? = null + private val c: ProxyContainer = container - override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy): Any? { + override fun clearCache() { + cache = null + } + + override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy?): Any? { var cache = this.cache if (cache != null) { - return cache(target, container, method, args, proxy) + return cache(target, c, method, args, proxy) } - val methodCache = container.ctx[ProxyMethodCache.ctxKey] + proxy!! + + val methodCache = c.ctx[ProxyMethodCache.ctxKey] this.cache = methodCache[proxy] cache = this.cache if (cache != null) { - return cache(target, container, method, args, proxy) + return cache(target, c, method, args, proxy) } return super.intercept(target, method, args, proxy) diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt index 3086a09..c5374cd 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt @@ -13,25 +13,25 @@ import net.sf.cglib.proxy.MethodProxy import java.lang.reflect.Method open class ProxyInterceptor( - val container: ProxyContainer = ListProxyContainer(), - val nonProxyClasses: MutableSet> = HashSet(listOf(Any::class.java)), + val container: ProxyContainer = ListProxyContainer(nonProxyClasses = HashSet(listOf(Any::class.java))), ) : MethodInterceptor { - override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy): Any? { + override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy?): Any? { val cache = container.ctx[ProxyMethodCache.ctxKey] - var handler = cache[proxy] + var handler = cache[proxy!!] if (handler != null) { return handler(obj, container, method, args, proxy) } + obj!! method!! - nonProxyClasses.forEach { nonProxyClass -> + container.nonProxyClasses.forEach { nonProxyClass -> nonProxyClass.declaredMethods.forEach { if (it.name == method.name && it.returnType.isAssignableFrom(method.returnType) && it.parameterTypes.contentEquals(method.parameterTypes) ) { - cache.update(proxy, CallSuperProxyMethodCacheFunction) + cache.update(obj, container, method, proxy, CallSuperProxyMethodCacheFunction[obj, method]) return proxy.invokeSuper(obj, args) } } 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 967fede..9c2240e 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 @@ -2,37 +2,32 @@ package cn.tursom.proxy import cn.tursom.core.allFieldsSequence import cn.tursom.core.static +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import cn.tursom.proxy.function.ProxyMethod import com.esotericsoftware.reflectasm.MethodAccess import net.sf.cglib.proxy.InvocationHandler import net.sf.cglib.proxy.MethodProxy import org.junit.Test import org.objectweb.asm.ClassWriter import java.io.File +import java.lang.reflect.Method class Example { - companion object{ + companion object { var bytes: ByteArray? = null - - fun saveBytes(b: ByteArray) { - bytes = b - } } open class TestClass protected constructor() { - open var a: Int = 0 + open var a: Int? = 0 } class GetA( t: TestClass, - ) { + ) : ProxyMethod { val t: TestClass = Proxy.getSuperCaller(t) - val a: Int - get() = t.a + 1 - - //fun getA(): Int { - // return t.a + 1 - //} + val a get() = (t.a ?: 0) + 1 } @Test @@ -95,9 +90,35 @@ class Example { container.addProxy(GetA(t)) println(t.javaClass) - repeat(1000000000) { + for (l in 0..10_000_000_000L) { t.a = t.a - //println(t.a) + } + } + + interface IntContainer { + var i: Int? + } + + class IntContainerImpl(override var i: Int?) : IntContainer + + class IntProxy( + private val c: IntContainer, + ) : IntContainer { + override var i: Int? + get() = (c.i ?: 0) + 1 + set(value) { + c.i = value + } + } + + private val a: IntContainerImpl = IntContainerImpl(0) + + @Test + fun benchmarkOrigin() { + val p: IntContainer = IntProxy(a) + + for (l in 0..10000000000L) { + p.i = p.i } } } \ No newline at end of file diff --git a/ts-core/ts-reflectasm/src/main/java/cn/tursom/reflect/asm/ReflectAsmInvoker.java b/ts-core/ts-reflectasm/src/main/java/cn/tursom/reflect/asm/ReflectAsmInvoker.java new file mode 100644 index 0000000..8f01093 --- /dev/null +++ b/ts-core/ts-reflectasm/src/main/java/cn/tursom/reflect/asm/ReflectAsmInvoker.java @@ -0,0 +1,19 @@ +package cn.tursom.reflect.asm; + +import com.esotericsoftware.reflectasm.MethodAccess; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ReflectAsmInvoker { + @Nullable + public static Object invoke(MethodAccess methodAccess, Object obj, int index, Object[] args) { + return methodAccess.invoke(obj, index, args); + } + + @Nullable + public static Object invoke(Method method, Object obj, Object[] args) throws InvocationTargetException, IllegalAccessException { + return method.invoke(obj, args); + } +} 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 abb2740..4186b79 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 @@ -62,6 +62,7 @@ object ReflectAsmUtils { } catch (_: Exception) { } } + fieldAccessList.add(MethodAccess.get(analyzeFieldAccessClass)!!) methodAccessMap[this] = fieldAccessList fieldAccessList } @@ -84,6 +85,41 @@ object ReflectAsmUtils { return null } + fun getMethodSequence( + clazz: Class<*>, + methodName: String, + vararg paramTypes: Class<*>, + returnType: Class<*> = Any::class.java, + ) = sequence { + clazz.methodAccessList.forEach { methodAccess -> + repeat(methodAccess.methodNames.size) { i -> + if (methodAccess.methodNames[i] == methodName && methodAccess.parameterTypes[i] match paramTypes && + methodAccess.returnTypes[i] canCast returnType + ) { + yield(methodAccess to i) + } + } + } + } + + fun getMethodByRegex( + clazz: Class<*>, + methodName: Regex, + vararg paramTypes: Class<*>, + returnType: Class<*> = Any::class.java, + ): Pair? { + clazz.methodAccessList.forEach { methodAccess -> + repeat(methodAccess.methodNames.size) { i -> + if (methodName.matches(methodAccess.methodNames[i]) && methodAccess.parameterTypes[i] match paramTypes && + methodAccess.returnTypes[i] canCast returnType + ) { + return methodAccess to i + } + } + } + return null + } + fun getMethod(method: Method): Pair? = getMethod( method.declaringClass, method.name, diff --git a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlFormatter.kt b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlFormatter.kt index 435e297..0d6c3fa 100644 --- a/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlFormatter.kt +++ b/ts-database/ts-ktorm/src/main/kotlin/cn/tursom/database/ktorm/ext/ExtSqlFormatter.kt @@ -1,6 +1,6 @@ package cn.tursom.database.ktorm.ext -import cn.tursom.proxy.ProxyMethod +import cn.tursom.proxy.function.ProxyMethod import cn.tursom.reflect.asm.ReflectAsmKtField import org.ktorm.expression.SqlExpression import org.ktorm.expression.SqlFormatter diff --git a/ts-gradle/build.gradle.kts b/ts-gradle/build.gradle.kts index 34c79f9..7c6f824 100644 --- a/ts-gradle/build.gradle.kts +++ b/ts-gradle/build.gradle.kts @@ -2,7 +2,7 @@ import java.util.* plugins { - kotlin("jvm") version "1.3.72" + kotlin("jvm") version "1.7.10" `java-gradle-plugin` `maven-publish` } @@ -14,10 +14,10 @@ try { ext.set(k.toString(), v) try { setProperty(k.toString(), v) - } catch (e: Exception) { + } catch (_: Exception) { } } -} catch (e: Exception) { +} catch (_: Exception) { } group = "cn.tursom" @@ -25,11 +25,13 @@ group = "cn.tursom" version = "1.0-SNAPSHOT" repositories { - mavenCentral() + maven { + url = uri("https://nvm.tursom.cn/repository/maven-public/") + } } dependencies { - implementation(group = "org.yaml", name = "snakeyaml", version = "1.29") + implementation(group = "org.yaml", name = "snakeyaml", version = "1.33") implementation(fileTree(mapOf("dir" to "libs", "include" to arrayOf("*.jar")))) } @@ -60,7 +62,7 @@ publishing { } } } catch (e: Exception) { - println("cannot push to repository tursom") + println("cannot push to repository tursom: ${e.javaClass}: ${e.message}") } try { maven { diff --git a/ts-gradle/src/main/kotlin/Utils.kt b/ts-gradle/src/main/kotlin/Utils.kt index 738fda0..6344bd0 100644 --- a/ts-gradle/src/main/kotlin/Utils.kt +++ b/ts-gradle/src/main/kotlin/Utils.kt @@ -1,12 +1,15 @@ import org.gradle.api.DomainObjectCollection +import org.gradle.api.NamedDomainObjectCollection import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.dsl.RepositoryHandler +import org.gradle.api.artifacts.repositories.PasswordCredentials +import org.gradle.api.publish.PublicationContainer import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication +import org.gradle.internal.authentication.DefaultBasicAuthentication import java.util.concurrent.TimeUnit -var nettyVersion = "4.1.68.Final" - fun Project.excludeTest() { if (gradle.startParameter.taskNames.firstOrNull { taskName -> taskName.contains("test", true) @@ -17,92 +20,13 @@ fun Project.excludeTest() { named("compileTestJava") { it.enabled = false } try { named("compileTestKotlin") { it.enabled = false } - } catch (e: Exception) { + } catch (_: Exception) { } named("processTestResources") { it.enabled = false } } } } -fun Project.publish(publish: PublishingExtension) { - val properties = rootProject.properties - publish.repositories { repositoryHandler -> - try { - repositoryHandler.maven { repository -> - repository.name = "tursom" - repository.url = if (version.toString().endsWith("SNAPSHOT")) { - uri("https://nvm.tursom.cn/repository/maven-snapshots/") - } else { - uri("https://nvm.tursom.cn/repository/maven-releases/") - } - repository.credentials { credentials -> - val artifactoryUser: String = rootProject.ext["tursom.artifactoryUser"]!!.toString() - val artifactoryPassword: String = rootProject.ext["tursom.artifactoryPassword"]!!.toString() - credentials.username = artifactoryUser - credentials.password = artifactoryPassword - } - } - } catch (e: Exception) { - println("cannot publish to repository tursom:\n${e.javaClass}: ${e.message}") - } - - val repositoriesRegex = "publishRepositories\\.[a-zA-z][a-zA-z0-9]*".toRegex() - properties.keys.asSequence().filter { - it matches repositoriesRegex - }.forEach { repositoryName -> - try { - val artifactoryUser = rootProject.ext["$repositoryName.artifactoryUser"]?.toString() - ?: throw Exception("no artifactory user found") - val artifactoryPassword = rootProject.ext["$repositoryName.artifactoryPassword"]?.toString() - ?: throw Exception("no artifactory password found") - repositoryHandler.maven { repository -> - repository.name = properties["$repository.name"]?.toString() - ?: repositoryName.substringAfterLast('.') - val releasesRepoUrl = properties["$repositoryName.release"]?.let { - uri(it.toString()) - } - val snapshotRepoUrl = properties["$repositoryName.snapshot"]?.let { - uri(it.toString()) - } - val repoUrl = properties["$repositoryName.url"]?.let { - uri(it.toString()) - } - repository.url = if (version.toString().endsWith("SNAPSHOT") && snapshotRepoUrl != null) { - snapshotRepoUrl - } else { - releasesRepoUrl - } ?: repoUrl ?: throw Exception("no repo found") - repository.credentials { - it.username = artifactoryUser - it.password = artifactoryPassword - } - } - } catch (e: Exception) { - println( - "cannot publish to repository ${repositoryName.substringAfterLast('.')}:\n" + - "${e.javaClass}: ${e.message}" - ) - } - } - } - publish.publications { - it.create("maven", MavenPublication::class.java) { mavenPublication -> - mavenPublication.groupId = project.group.toString() - mavenPublication.artifactId = project.name - mavenPublication.version = project.version.toString() - - try { - mavenPublication.from(components.getByName("java")) - } catch (e: Exception) { - } - try { - mavenPublication.artifact(tasks.getByName("kotlinSourcesJar")) - } catch (e: Exception) { - } - } - } -} - fun DomainObjectCollection.noExpire() { all { it.resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) @@ -110,7 +34,7 @@ fun DomainObjectCollection.noExpire() { } } -fun Project.userTursomRepositories( +fun Project.useTursomRepositories( useAliyunMirror: Boolean = false, mavenCentral: Boolean = false, tursom: Boolean = true @@ -132,6 +56,19 @@ fun Project.userTursomRepositories( } try { configurations.noExpire() - } catch (e: Exception) { + } catch (_: Exception) { } } + +fun NamedDomainObjectCollection.contains(name: String) = try { + findByName(name) +} catch (e: Exception) { + null +} != null + +operator fun Project.get(key: String) = ext[key]?.toString() + +val Project.isTestRunning + get() = gradle.startParameter.taskNames.firstOrNull { taskName -> + taskName.endsWith(":test") + } != null diff --git a/ts-gradle/src/main/kotlin/cn/tursom/gradle/TursomGradlePlugin.kt b/ts-gradle/src/main/kotlin/cn/tursom/gradle/TursomGradlePlugin.kt index 0e8971d..d64af28 100644 --- a/ts-gradle/src/main/kotlin/cn/tursom/gradle/TursomGradlePlugin.kt +++ b/ts-gradle/src/main/kotlin/cn/tursom/gradle/TursomGradlePlugin.kt @@ -1,5 +1,6 @@ package cn.tursom.gradle +import contains import excludeTest import ext import org.gradle.api.DefaultTask @@ -37,19 +38,7 @@ class TursomGradlePlugin : Plugin { target.excludeTest() - try { - target.extensions.configure("publishing") { - target.publish(it) - } - } catch (e: Exception) { - } - - if (try { - target.tasks.findByName("install") - } catch (e: Exception) { - null - } == null - ) run install@{ + if (!target.tasks.contains("install")) run install@{ val publishToMavenLocal = target.tasks.findByName("publishToMavenLocal") ?: return@install target.tasks.register("install", DefaultTask::class.java) { it.finalizedBy(publishToMavenLocal) @@ -85,6 +74,7 @@ fun put(target: Project, key: String, value: Any?) { null -> return is String, is Byte, is Short, is Int, is Long, is Float, is Double, is Char -> setProperty(target, key, value) + else -> { setProperty(target, key, value) if (value is Map<*, *>) { diff --git a/ts-gradle/src/main/kotlin/consts.kt b/ts-gradle/src/main/kotlin/consts.kt new file mode 100644 index 0000000..1bf4810 --- /dev/null +++ b/ts-gradle/src/main/kotlin/consts.kt @@ -0,0 +1 @@ +var nettyVersion = "4.1.68.Final" diff --git a/ts-gradle/src/main/kotlin/publish.kt b/ts-gradle/src/main/kotlin/publish.kt new file mode 100644 index 0000000..9630c50 --- /dev/null +++ b/ts-gradle/src/main/kotlin/publish.kt @@ -0,0 +1,176 @@ +import org.gradle.api.Project +import org.gradle.api.artifacts.dsl.RepositoryHandler +import org.gradle.api.artifacts.repositories.PasswordCredentials +import org.gradle.api.publish.PublicationContainer +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.authentication.http.BasicAuthentication + +fun Project.autoConfigPublish() { + try { + extensions.configure("publishing", ::publish) + } catch (e: Exception) { + println("auto config publish failed: ${e.javaClass} ${e.message}") + } +} + +fun Project.publish(publish: PublishingExtension) { + publish.repositories { repositoryHandler -> + createTursomPublishRepository(repositoryHandler) + scanAndCreatePublishRepository(repositoryHandler) + } + + publish.publications(::createMavenPublications) +} + +/** + * create publish repository for tursom's server + */ +private fun Project.createTursomPublishRepository(repositoryHandler: RepositoryHandler) { + try { + repositoryHandler.maven { repository -> + repository.name = "tursom" + val version = getVersionWithProperties() + if (warnVersionNotSet(version)) { + return@maven + } + + repository.url = if (version.endsWith("SNAPSHOT")) { + uri("https://nvm.tursom.cn/repository/maven-snapshots/") + } else { + uri("https://nvm.tursom.cn/repository/maven-releases/") + } + + repository.authentication{ ac -> + ac.forEach { + + } + } + + repository.credentials(PasswordCredentials::class.java) { credentials -> + val artifactoryUser: String = rootProject.ext["tursom.artifactoryUser"]!!.toString() + val artifactoryPassword: String = rootProject.ext["tursom.artifactoryPassword"]!!.toString() + credentials.username = artifactoryUser + credentials.password = artifactoryPassword + } + } + } catch (e: Exception) { + println("cannot publish to repository tursom:\n${e.javaClass}: ${e.message}") + } +} + +/** + * scan properties begin with "publishRepositories" to create user defined publish repository + */ +private fun Project.scanAndCreatePublishRepository(repositoryHandler: RepositoryHandler) { + val properties = rootProject.properties + val repositoriesRegex = "^publishRepositories\\.[a-zA-z][a-zA-z0-9]*$".toRegex() + + properties.keys.asSequence().filter { + it matches repositoriesRegex + }.forEach { repositoryName -> + try { + val artifactoryUser = rootProject.ext["$repositoryName.artifactoryUser"]?.toString() + ?: throw Exception("no artifactory user found") + val artifactoryPassword = rootProject.ext["$repositoryName.artifactoryPassword"]?.toString() + ?: throw Exception("no artifactory password found") + repositoryHandler.maven { repository -> + repository.name = properties["$repository.name"]?.toString() + ?: repositoryName.substringAfterLast('.') + val releasesRepoUrl = properties["$repositoryName.release"]?.let { + uri(it.toString()) + } + val snapshotRepoUrl = properties["$repositoryName.snapshot"]?.let { + uri(it.toString()) + } + val repoUrl = properties["$repositoryName.url"]?.let { + uri(it.toString()) + } + repository.url = if (version.toString().endsWith("SNAPSHOT") && snapshotRepoUrl != null) { + snapshotRepoUrl + } else { + releasesRepoUrl + } ?: repoUrl ?: throw Exception("no repo found") + repository.credentials { + it.username = artifactoryUser + it.password = artifactoryPassword + } + } + } catch (e: Exception) { + println( + "cannot publish to repository ${repositoryName.substringAfterLast('.')}:\n" + + "${e.javaClass}: ${e.message}" + ) + } + } +} + +private fun Project.createMavenPublications(pc: PublicationContainer) { + pc.maybeCreate("maven", MavenPublication::class.java).let { mavenPublication -> + + val groupId = project.group.toString() + .ifBlank { ext.properties["project.groupId"]?.toString() } + if (warnGroupIdNotSet(groupId)) { + return + } + + val version = getVersionWithProperties() + if (warnVersionNotSet(version)) { + return + } + + mavenPublication.groupId = groupId + mavenPublication.artifactId = project.name + mavenPublication.version = version + + try { + mavenPublication.from(components.getByName("java")) + } catch (_: Exception) { + } + try { + mavenPublication.artifact(tasks.getByName("kotlinSourcesJar")) + } catch (_: Exception) { + } + } +} + +/** + * warn user that group id is not set. + * @return true if group id is not set + * false if group id is set. + */ +private fun Project.warnGroupIdNotSet(groupId: String?) = if (groupId.isNullOrEmpty()) { + println( + "cannot publish to maven of project $this cause group id is not set. " + + "you can specific property \"project.groupId\" to solve it." + ) + true +} else { + false +} + +/** + * warn user that group id is not set. + * @return true if group id is not set + * false if group id is set. + */ +private fun Project.warnVersionNotSet(version: String?) = if (isEmptyVersion(version)) { + println( + "cannot publish to maven of project $this cause version is not set. " + + "you can specific property \"project.version\" to solve it." + ) + true +} else { + false +} + +private fun isEmptyVersion(version: String?) = version.isNullOrEmpty() || version == Project.DEFAULT_VERSION + +private fun Project.getVersionWithProperties(): String { + var version = this.version.toString() + if (isEmptyVersion(version)) { + version = ext["project.version"]?.toString() ?: Project.DEFAULT_VERSION + } + + return version +} \ No newline at end of file diff --git a/ts-web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt b/ts-web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt index 0d5f46a..5382fb9 100644 --- a/ts-web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt +++ b/ts-web/src/main/kotlin/cn/tursom/web/router/RoutedHttpHandler.kt @@ -313,7 +313,6 @@ open class RoutedHttpHandler( fun autoReturn(result: Any?, content: HttpContent, doLog: Boolean = true) { if (content.finished || result is Unit) return if (doLog) log?.debug("{}: autoReturn: {}", content.remoteAddress, result) - result ?: return when (result) { null -> content.finish(404) is ByteBuffer -> content.finishText(result) @@ -336,7 +335,6 @@ open class RoutedHttpHandler( fun finishHtml(result: Any?, content: HttpContent, doLog: Boolean = true) { if (content.finished || result is Unit) return if (doLog) log?.debug("{} finishHtml {}", content.remoteAddress, result) - result ?: return when (result) { null -> content.finish(404) is ByteBuffer -> content.finishHtml(result) @@ -355,7 +353,6 @@ open class RoutedHttpHandler( fun finishText(result: Any?, content: HttpContent, doLog: Boolean = true) { if (content.finished || result is Unit) return if (doLog) log?.debug("{} finishText {}", content.remoteAddress, result) - result ?: return when (result) { null -> content.finish(404) is ByteBuffer -> content.finishText(result) @@ -374,7 +371,6 @@ open class RoutedHttpHandler( fun finishJson(result: Any?, content: HttpContent, doLog: Boolean = true) { if (content.finished || result is Unit) return if (doLog) log?.debug("{} finishJson {}", content.remoteAddress, result) - result ?: return when (result) { null -> content.finish(404) is ByteBuffer -> content.finishJson(result) diff --git a/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyChunkedInput.kt b/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyChunkedInput.kt index 8eca93f..94b237a 100644 --- a/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyChunkedInput.kt +++ b/ts-web/ts-web-netty/src/main/kotlin/cn/tursom/web/netty/NettyChunkedInput.kt @@ -15,6 +15,7 @@ class NettyChunkedInput(private val chunked: Chunked) : ChunkedInput { override fun length() = chunked.length override fun isEndOfInput(): Boolean = chunked.endOfInput + @Deprecated("Deprecated in Java", ReplaceWith("readChunk(allocator)")) override fun readChunk(ctx: ChannelHandlerContext?): ByteBuf = readChunk() override fun readChunk(allocator: ByteBufAllocator?): ByteBuf = readChunk()