diff --git a/build.gradle.kts b/build.gradle.kts index 06b3bb4..4837405 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ ext["excludeTest"] = { project: Project, tasks: TaskContainer -> plugins { - kotlin("jvm") version "1.4.31" + kotlin("jvm") version "1.4.32" `maven-publish` } @@ -44,6 +44,12 @@ allprojects { } } } + + tasks.withType().configureEach { + kotlinOptions.jvmTarget = "1.8" + kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" + //kotlinOptions.useIR = true + } } @kotlin.Suppress("UNCHECKED_CAST") @@ -53,9 +59,10 @@ dependencies { api(kotlin("stdlib-jdk8")) api(kotlin("reflect")) testImplementation(group = "junit", name = "junit", version = "4.12") +} - val commonVersion = "1.0.RELEASE" - api("com.ddbes", "common-kotlin", commonVersion) +artifacts { + archives(tasks["kotlinSourcesJar"]) } tasks.register("install") { @@ -71,7 +78,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 3cca404..59619f7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,6 +7,7 @@ include("ts-core:ts-pool") include("ts-core:ts-hash") include("ts-core:ts-log") include("ts-core:ts-delegation") +include("ts-core:ts-delegation:ts-observer") include("ts-core:ts-clone") include("ts-core:ts-mail") include("ts-core:ts-coroutine") @@ -14,10 +15,16 @@ include("ts-core:ts-coroutine:ts-coroutine-lock") include("ts-core:ts-ws-client") include("ts-core:ts-yaml") include("ts-core:ts-json") +include("ts-core:ts-xml") +include("ts-core:ts-async-http") include("ts-socket") include("ts-web") include("ts-web:ts-web-netty") include("ts-web:ts-web-coroutine") +include("ts-database") +include("ts-database:ts-mongodb") +include("ts-database:ts-mongodb:ts-mongodb-spring") +include("ts-database:ts-redis") //include("web", "aop", "database", "utils", "utils:xml", "utils:async-http", "web:netty-web") //include("socket", "socket:socket-async") //include("AsyncSocket") diff --git a/ts-core/build.gradle.kts b/ts-core/build.gradle.kts index 53a3b36..5a7bd4c 100644 --- a/ts-core/build.gradle.kts +++ b/ts-core/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } dependencies { - implementation(project(":")) + api(project(":")) compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.6") compileOnly(group = "io.netty", name = "netty-all", version = "4.1.43.Final") } @@ -25,7 +25,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/src/main/kotlin/cn/tursom/core/InstantAllocator.kt b/ts-core/src/main/kotlin/cn/tursom/core/InstantAllocator.kt new file mode 100644 index 0000000..d279c8f --- /dev/null +++ b/ts-core/src/main/kotlin/cn/tursom/core/InstantAllocator.kt @@ -0,0 +1,53 @@ +package cn.tursom.core + +import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.KClass + +object InstantAllocator { + enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE } + + private val allocateFunctionMap = ConcurrentHashMap, AllocateFunction>() + + @Throws(NoSuchMethodException::class) + operator fun invoke(clazz: Class, unsafe: Boolean = true): T = get(clazz, unsafe) + + @Throws(NoSuchMethodException::class) + inline operator fun invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe) + + @Throws(NoSuchMethodException::class) + operator fun get(clazz: KClass, unsafe: Boolean = true): T = get(clazz.java, unsafe) + + @Throws(NoSuchMethodException::class) + operator fun get(clazz: Class, unsafe: Boolean = true): T { + return when (allocateFunctionMap[clazz]) { + null -> try { + val newInstance = clazz.newInstance() + allocateFunctionMap[clazz] = AllocateFunction.INSTANCE + newInstance + } catch (e: Exception) { + val kClass = clazz.kotlin + val objectInstance = kClass.objectInstance + if (objectInstance != null) { + allocateFunctionMap[clazz] = AllocateFunction.KOBJECT + objectInstance + } else if (unsafe) try { + allocateFunctionMap[clazz] = AllocateFunction.UNSAFE + Unsafe.unsafe.allocateInstance(clazz).uncheckedCast() + } catch (e: Exception) { + allocateFunctionMap[clazz] = AllocateFunction.NONE + throw NoSuchMethodException("${clazz.name}:()") + } else { + throw NoSuchMethodException("${clazz.name}:()") + } + } + AllocateFunction.INSTANCE -> clazz.newInstance() + AllocateFunction.UNSAFE -> if (unsafe) { + Unsafe.unsafe.allocateInstance(clazz).uncheckedCast() + } else { + throw NoSuchMethodException("${clazz.name}:()") + } + AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!! + AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:()") + } + } +} \ No newline at end of file diff --git a/ts-core/src/main/kotlin/cn/tursom/core/Parser.kt b/ts-core/src/main/kotlin/cn/tursom/core/Parser.kt index 5272df7..f2f7083 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/Parser.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/Parser.kt @@ -66,11 +66,8 @@ object Parser { else -> { if (yaml !is Map<*, *>) return null - val instance = try { - clazz.newInstance() - } catch (e: Exception) { - unsafe.allocateInstance(clazz) - } + + val instance = InstantAllocator[clazz] val fields = clazz.declaredFields fields.forEach { if ((it.modifiers and (Modifier.STATIC or Modifier.TRANSIENT)) != 0) return@forEach diff --git a/ts-core/src/main/kotlin/cn/tursom/core/ScheduledExecutorPool.kt b/ts-core/src/main/kotlin/cn/tursom/core/ScheduledExecutorPool.kt new file mode 100644 index 0000000..be89dc0 --- /dev/null +++ b/ts-core/src/main/kotlin/cn/tursom/core/ScheduledExecutorPool.kt @@ -0,0 +1,41 @@ +package cn.tursom.core + +import java.util.concurrent.* +import java.util.concurrent.atomic.AtomicInteger + +class ScheduledExecutorPool( + private val threadCount: Int = Runtime.getRuntime().availableProcessors() * 2, + private val threadFactory: ThreadFactory = Executors.defaultThreadFactory(), +) { + private val scheduledExecutorQueue = ConcurrentLinkedDeque>() + private var initCount = AtomicInteger() + + init { + initOne() + } + + private fun initOne() { + if (initCount.incrementAndGet() < threadCount) { + val executor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor { + threadFactory.newThread(it) + } + val countDownLatch = CountDownLatch(1) + executor.execute { + scheduledExecutorQueue.addFirst(Thread.currentThread() to executor) + countDownLatch.countDown() + } + countDownLatch.await(3, TimeUnit.SECONDS) + } else { + initCount.decrementAndGet() + } + } + + fun get(): Pair { + if (initCount.get() < threadCount) { + initOne() + } + val pair = scheduledExecutorQueue.poll() + scheduledExecutorQueue.add(pair) + return pair + } +} \ No newline at end of file diff --git a/ts-core/src/main/kotlin/cn/tursom/core/SimpThreadLocal.kt b/ts-core/src/main/kotlin/cn/tursom/core/SimpThreadLocal.kt index 120bad7..65b4469 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/SimpThreadLocal.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/SimpThreadLocal.kt @@ -1,12 +1,26 @@ package cn.tursom.core -open class SimpThreadLocal(private val new: () -> T) : ThreadLocal() { - override fun get(): T = super.get() ?: update() +open class SimpThreadLocal( + private val threadLocal: ThreadLocal? = null, + val new: () -> T, +) : ThreadLocal() { + override fun get(): T { + var value = if (threadLocal != null) threadLocal.get() else super.get() + return if (value == null) { + value = new() + set(value) + value + } else { + value + } + } - private fun update(): T { - val value = new() - set(value) - return value + override fun set(value: T) { + if (threadLocal != null) threadLocal.set(value) else super.set(value) + } + + override fun remove() { + if (threadLocal != null) threadLocal.remove() else super.remove() } } diff --git a/ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt b/ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt new file mode 100644 index 0000000..32accfe --- /dev/null +++ b/ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt @@ -0,0 +1,123 @@ +package cn.tursom.core + +object TextColor { + const val reset = "\u001b[0m" + + enum class DisplayType(val code: Int) { + DEFAULT(0), HIGHLIGHT(1), INTENSITY(2), ITALIC(3), UNDERLINE(4), + SLOW_BLINK(5), RAPID_BLINK(6), REVERSE(7), INVISIBLE(8), CROSSED_OUT(9), + UNDERLINE_OFF(24), BLINK_OFF(25), REVERSE_OFF(27), INVISIBLE_OFF(28), CROSSED_OUT_OFF(29), + OVER_LINE(53), OVER_LINE_OFF(55); + + val strCode = "\u001b[${code}m" + } + + fun textColor(displayType: DisplayType, textColor: Int, backgroundColor: Int) = + "\u001B[${displayType.code};$textColor;${backgroundColor}m" + + fun rgbTextColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) = + "\u001B[${displayType.code};38;2;$r;$g;${b}m" + + fun rgbBackgroundColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) = + "\u001B[${displayType.code};48;2;$r;$g;${b}m" + + const val black = "\u001b[30m" + const val red = "\u001b[31m" + const val green = "\u001b[32m" + const val yellow = "\u001b[33m" + const val blue = "\u001b[34m" + const val magenta = "\u001b[35m" + const val cyan = "\u001b[36m" + const val white = "\u001b[37m" + + const val brightBlack = "\u001b[30;1m" + const val brightRed = "\u001b[31;1m" + const val brightGreen = "\u001b[32;1m" + const val brightYellow = "\u001b[33;1m" + const val brightBlue = "\u001b[34;1m" + const val brightMagenta = "\u001b[35;1m" + const val brightCyan = "\u001b[36;1m" + const val brightWhite = "\u001b[37;1m" + + val textColor = Array(256) { + "\u001b[38;5;${it}m" + } + + fun textColor(color: Int) = textColor[color] + fun textColor(color: Int, displayType: DisplayType = DisplayType.DEFAULT) = + "\u001B[${displayType.code};38;5;${color}m" + + const val blackBackground = "\u001b[40m" + const val redBackground = "\u001b[41m" + const val greenBackground = "\u001b[42m" + const val yellowBackground = "\u001b[43m" + const val blueBackground = "\u001b[44m" + const val magentaBackground = "\u001b[45m" + const val cyanBackground = "\u001b[46m" + const val whiteBackground = "\u001b[47m" + + const val brightBlackBackground = "\u001b[40;1m" + const val brightRedBackground = "\u001b[41;1m" + const val brightGreenBackground = "\u001b[42;1m" + const val brightYellowBackground = "\u001b[43;1m" + const val brightBlueBackground = "\u001b[44;1m" + const val brightMagentaBackground = "\u001b[45;1m" + const val brightCyanBackground = "\u001b[46;1m" + const val brightWhiteBackground = "\u001b[47;1m" + + val backgroundColor = Array(256) { + "\u001b[48;5;${it}m" + } + + const val bold = "\u001b[1m" + const val underline = "\u001b[4m" + const val reverseColor = "\u001b[7m" + + const val up = "\u001b[1A" + const val down = "\u001b[1B" + const val left = "\u001b[1C" + const val right = "\u001b[1D" + + const val downToNextLine = "\u001b[1E" + const val upToPrevLine = "\u001b[1F" + + fun up(step: Int) = "\u001b[${step}A" + fun down(step: Int) = "\u001b[${step}B" + fun left(step: Int) = "\u001b[${step}C" + fun right(step: Int) = "\u001b[${step}D" + + fun downToNextLine(step: Int) = "\u001b[${step}E" + fun upToPrevLine(step: Int) = "\u001b[${step}F" + + fun jumpToLine(line: Int) = "\u001b[${line}G" + fun jump(line: Int, row: Int) = "\u001b[${line};${row}H" + + const val cleanScreenToEnd = "\u001b[0J" + const val cleanScreenFromStart = "\u001b[1J" + const val cleanScreen = "\u001b[2J" + + const val cleanLineToEnd = "\u001b[0K" + const val cleanLineFromStart = "\u001b[1K" + const val cleanLine = "\u001b[2K" + + const val savePosition = "\u001b[s" + const val loadPosition = "\u001b[u" + + fun rgbTo8Color(R: Int, G: Int, B: Int): Int { + //8色化处理,取RGB的高1位相与。 + val r1 = R shr 5 and 0x4 + val g1 = G shr 6 and 0x2 + val b1 = B shr 7 + return (r1 or g1 or b1) + 1 + } + + fun rgbTo16Color(R: Int, G: Int, B: Int): Int { + //16色化处理,取R、G的高1位和B的高2位相与 + val r1 = R shr 4 and 0x8 + val g1 = G shr 5 and 0x4 + val b1 = B shr 6 and 0x3 + return (r1 or g1 or b1) + 1 + } + + fun rgbTo256Color(r: Int, g: Int, b: Int): Int = ((r / 32 shl 5) + (g / 32 shl 2) + b / 64) and 0xFF +} diff --git a/ts-core/src/main/kotlin/cn/tursom/core/ThreadLocalSimpleDateFormat.kt b/ts-core/src/main/kotlin/cn/tursom/core/ThreadLocalSimpleDateFormat.kt index 29c267a..38c5364 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/ThreadLocalSimpleDateFormat.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/ThreadLocalSimpleDateFormat.kt @@ -4,8 +4,8 @@ import java.text.SimpleDateFormat import java.util.* class ThreadLocalSimpleDateFormat( - val format: String = "YYYY-MM-dd'T'HH:mm:ssZZ" -) : SimpThreadLocal({ + val format: String = "YYYY-MM-dd'T'HH:mm:ssZZ", +) : SimpThreadLocal(null, { SimpleDateFormat(format) }) { fun format(date: Any) = get().format(date) diff --git a/ts-core/src/main/kotlin/cn/tursom/core/Tools.kt b/ts-core/src/main/kotlin/cn/tursom/core/Tools.kt index b24adc7..e4ddb08 100644 --- a/ts-core/src/main/kotlin/cn/tursom/core/Tools.kt +++ b/ts-core/src/main/kotlin/cn/tursom/core/Tools.kt @@ -53,8 +53,12 @@ object Utils { .create() } + @Suppress("SpellCheckingInspection") internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray() + + @Suppress("SpellCheckingInspection") internal val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray() + val md5 by lazy { MessageDigest.getInstance("MD5")!! } val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! } val sha by lazy { MessageDigest.getInstance("SHA")!! } @@ -62,6 +66,7 @@ object Utils { val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! } val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! } + @Suppress("SpellCheckingInspection") internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray() val receiverField: Field by lazy { @@ -112,9 +117,18 @@ inline fun Iterable.toSetNotNull(transform: (T) -> R?): Set { } +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +//@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class UncheckedCast + +@UncheckedCast @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") inline fun Any?.cast() = this as T +@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") +inline fun Any?.uncheckedCast() = this as T + @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") inline fun Any?.castOrNull() = if (this is T) this else null @@ -126,7 +140,7 @@ inline fun T?.checkNull(ifNull: () -> Exception): T { } } -fun String.emptyToNull() = if (isEmpty()) null else this +fun String.emptyToNull() = ifEmpty { null } inline fun getClazz() = T::class.java @@ -242,7 +256,7 @@ fun A.changeAnnotationValue(field: KProperty1, v val h = Proxy.getInvocationHandler(this) val memberValuesField = h.javaClass.getDeclaredField("memberValues") memberValuesField.isAccessible = true - val memberValues = memberValuesField[h].cast>() + val memberValues = memberValuesField[h].uncheckedCast>() memberValues[field.name] = value true } catch (e: Exception) { @@ -280,12 +294,7 @@ inline fun usingNanoTime(action: () -> Unit): Long { } inline fun Class<*>.forAllFields(action: (Field) -> Unit) { - var clazz = this - while (clazz != Any::class.java) { - clazz.declaredFields.forEach(action) - clazz = clazz.superclass - } - clazz.declaredFields.forEach(action) + allFieldsSequence.forEach(action) } val Class<*>.allFields: List @@ -295,6 +304,17 @@ val Class<*>.allFields: List return fieldList } +val Class<*>.allFieldsSequence: Sequence + get() = sequence { + var clazz = this@allFieldsSequence + while (clazz != Any::class.java) { + clazz.declaredFields.forEach { field -> + yield(field) + } + clazz = clazz.superclass + } + } + fun Class<*>.getFieldForAll(name: String): Field? { forAllFields { if (it.name == name) return it @@ -303,12 +323,7 @@ fun Class<*>.getFieldForAll(name: String): Field? { } inline fun Class<*>.forAllMethods(action: (Method) -> Unit) { - var clazz = this - while (clazz != Any::class.java) { - clazz.declaredMethods.forEach(action) - clazz = clazz.superclass - } - clazz.declaredMethods.forEach(action) + allMethodsSequence.forEach(action) } fun Class<*>.getMethodForAll(name: String, vararg parameterTypes: Class<*>?): Method? { @@ -325,6 +340,20 @@ val Class<*>.allMethods: List return fieldList } +val Class<*>.allMethodsSequence: Sequence + get() = sequence { + var clazz = this@allMethodsSequence + while (clazz != Any::class.java) { + clazz.declaredMethods.forEach { + yield(it) + } + clazz = clazz.superclass + } + clazz.declaredMethods.forEach { + yield(it) + } + } + /** * 获取一个 KProperty<*> 对应的对象 */ @@ -342,7 +371,7 @@ val KProperty<*>.receiver: Any? val KProperty<*>.owner: Class<*>? get() = try { - Utils.ownerField.get(this)?.cast>() + Utils.ownerField.get(this)?.uncheckedCast>() } catch (e: Exception) { null } ?: javaClass.getFieldForAll("owner")?.let { @@ -382,16 +411,6 @@ fun Any.serialize(): ByteArray { return outputStream.toByteArray() } - -inline infix fun String.ifEmpty(ifEmpty: () -> String) = if (isNotEmpty()) this else ifEmpty() -inline infix fun String.ifBlank(ifBlank: () -> String) = if (isNotBlank()) this else ifBlank() - -@JvmName("ifEmptyNullable") -inline fun String.ifEmpty(ifEmpty: () -> String?) = if (isNotEmpty()) this else ifEmpty() - -@JvmName("ifBlankNullable") -inline fun String.ifBlank(ifBlank: () -> String?) = if (isNotBlank()) this else ifBlank() - /** * 使用 condition 做条件判断,如果返回 true 则使用 then 生成结果,否则范湖自身 */ @@ -428,9 +447,9 @@ inline val KClass<*>.companionObjectInstanceOrNull: Any? null } -inline val Map.notNullKey get() = cast>() -inline val Map.notNullValue get() = cast>() -inline val Map.notNullEntry get() = cast>() +inline val Map.notNullKey get() = uncheckedCast>() +inline val Map.notNullValue get() = uncheckedCast>() +inline val Map.notNullEntry get() = uncheckedCast>() inline val Map.filterNullKey get() = filter { it.key != null }.notNullKey inline val Map.filterNullValue get() = filter { it.value != null }.notNullValue @@ -442,7 +461,7 @@ val KClass.allMemberProperties: List> !it.java.isInterface } while (superClass != null) { - propertiesList.addAll(superClass.memberProperties.cast()) + propertiesList.addAll(superClass.memberProperties.uncheckedCast()) superClass = superClass.superclasses.firstOrNull { !it.java.isInterface } diff --git a/ts-core/ts-async-http/build.gradle.kts b/ts-core/ts-async-http/build.gradle.kts index 7e8f2cf..c5a21c6 100644 --- a/ts-core/ts-async-http/build.gradle.kts +++ b/ts-core/ts-async-http/build.gradle.kts @@ -1,20 +1,48 @@ -dependencies { - implementation(project(":")) - implementation(project(":utils")) - api project (":utils:xml") +plugins { + kotlin("jvm") + `maven-publish` +} - // kotlin 协程 - compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2' - // kotlin 反射 - //implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" - // OkHttp - //implementation("com.squareup.okhttp3:okhttp:3.14.1") - //implementation group: 'cglib', name: 'cglib', version: '3.3.0' - // https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson - api group : 'com.squareup.retrofit2', name: 'converter-gson', version: '2.9.0' +dependencies { + api(project(":")) + api(project(":ts-core")) + api(project(":ts-core:ts-buffer")) + implementation(project(":ts-core:ts-xml")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2") + api(group = "com.squareup.retrofit2", name = "converter-gson", version = "2.9.0") // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit - compile group : 'com.squareup.retrofit2', name: 'retrofit', version: '2.9.0' + api(group = "com.squareup.retrofit2", name = "retrofit", version = "2.9.0") // https://mvnrepository.com/artifact/org.jsoup/jsoup - api group : 'org.jsoup', name: 'jsoup', version: '1.13.1' + api(group = "org.jsoup", name = "jsoup", version = "1.13.1") + + + testImplementation(project(":ts-core:ts-coroutine")) +} + +@kotlin.Suppress("UNCHECKED_CAST") +(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks) + +tasks.register("install") { + finalizedBy(tasks["publishToMavenLocal"]) +} + +artifacts { + archives(tasks["kotlinSourcesJar"]) +} + +publishing { + publications { + create("maven") { + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + + from(components["java"]) + try { + artifact(tasks["kotlinSourcesJar"]) + } catch (e: Exception) { + } + } + } } diff --git a/ts-core/ts-async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt b/ts-core/ts-async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt index c1f2ae4..6de7522 100644 --- a/ts-core/ts-async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt +++ b/ts-core/ts-async-http/src/main/kotlin/cn/tursom/http/XmlConverterFactory.kt @@ -1,7 +1,7 @@ package cn.tursom.http import cn.tursom.core.isInheritanceFrom -import cn.tursom.utils.xml.Xml +import cn.tursom.core.xml.Xml import okhttp3.MediaType import okhttp3.RequestBody import okhttp3.ResponseBody diff --git a/ts-core/ts-async-http/src/test/kotlin/cn/tursom/http/test.kt b/ts-core/ts-async-http/src/test/kotlin/cn/tursom/http/test.kt index 67e5945..0b949fb 100644 --- a/ts-core/ts-async-http/src/test/kotlin/cn/tursom/http/test.kt +++ b/ts-core/ts-async-http/src/test/kotlin/cn/tursom/http/test.kt @@ -1,7 +1,7 @@ package cn.tursom.http -import cn.tursom.utils.coroutine.MainDispatcher -import cn.tursom.utils.gson +import cn.tursom.core.Utils.gson +import cn.tursom.core.coroutine.MainDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch diff --git a/ts-core/ts-buffer/build.gradle.kts b/ts-core/ts-buffer/build.gradle.kts index 7032e3f..7383fb7 100644 --- a/ts-core/ts-buffer/build.gradle.kts +++ b/ts-core/ts-buffer/build.gradle.kts @@ -15,6 +15,10 @@ tasks.register("install") { finalizedBy(tasks["publishToMavenLocal"]) } +artifacts { + archives(tasks["kotlinSourcesJar"]) +} + publishing { publications { create("maven") { @@ -24,7 +28,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-clone/build.gradle.kts b/ts-core/ts-clone/build.gradle.kts index e284acb..0316bd0 100644 --- a/ts-core/ts-clone/build.gradle.kts +++ b/ts-core/ts-clone/build.gradle.kts @@ -6,6 +6,7 @@ plugins { dependencies { implementation(project(":")) implementation(project(":ts-core")) + implementation(project(":ts-core:ts-log")) implementation(project(":ts-core:ts-datastruct")) } @@ -25,7 +26,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Key.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Key.kt index 2fbdc88..0a19909 100644 --- a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Key.kt +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Key.kt @@ -5,7 +5,7 @@ import kotlin.reflect.KClass @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FIELD) annotation class Key( - val key: String = "", - val clazz: KClass<*> = Any::class, - val handler: String = "" + val key: String = "", + val clazz: KClass<*> = Any::class, + val handler: String = "", ) diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/NoPropertyClone.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/NoPropertyClone.kt index 96bcc84..4f18278 100644 --- a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/NoPropertyClone.kt +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/NoPropertyClone.kt @@ -5,5 +5,5 @@ import kotlin.reflect.KClass @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.CLASS) annotation class NoPropertyClone( - vararg val classList: KClass<*> + vararg val classList: KClass<*>, ) \ No newline at end of file diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relation.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relation.kt index fd90faa..0ec149c 100644 --- a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relation.kt +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relation.kt @@ -5,11 +5,11 @@ import kotlin.reflect.KClass @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FIELD) annotation class Relation( - val clazz: KClass<*>, - val property: String = "", - val skip: Boolean = false, - val handler: String = "", - val handleClass: KClass<*> = Any::class + val clazz: KClass<*>, + val property: String = "", + val skip: Boolean = false, + val handler: String = "", + val handleClass: KClass<*> = Any::class, ) diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relations.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relations.kt index 84e0d94..3662356 100644 --- a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relations.kt +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/Relations.kt @@ -3,5 +3,5 @@ package cn.tursom.core.clone @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FIELD) annotation class Relations( - vararg val relations: Relation + vararg val relations: Relation, ) \ No newline at end of file diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/clone.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/clone.kt index 5ffc187..360d31d 100644 --- a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/clone.kt +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/clone.kt @@ -1,110 +1,22 @@ -@file:Suppress("unused") - package cn.tursom.core.clone -import cn.tursom.core.Unsafe -import cn.tursom.core.cast +import cn.tursom.core.* import cn.tursom.core.datastruct.ArrayMap -import cn.tursom.core.datastruct.KPropertyValueMap -import cn.tursom.core.datastruct.ReadWriteMap -import cn.tursom.core.datastruct.SoftArrayMap -import cn.tursom.core.final +import cn.tursom.log.impl.Slf4jImpl import kotlin.reflect.KClass -import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.memberProperties -import kotlin.reflect.jvm.isAccessible -import kotlin.reflect.jvm.javaField -import kotlin.reflect.jvm.javaType +/** + * clone 使用的日志对象 + */ +private val logger = Slf4jImpl.getLogger() +/** + * clone 使用的对象属性类型 + */ typealias Property = KProperty1 -val Any.valueMap: Map - get() = if (this is Map<*, *>) { - cast() - } else { - KPropertyValueMap(this) - } - -private val injectMapCache = ReadWriteMap, ArrayMap?>>(SoftArrayMap(HashMap())) - -val KClass.injectMap: ArrayMap?> - @Suppress("UNCHECKED_CAST") - get() = let { - var valueMap = injectMapCache[it] as ArrayMap?>? - if (valueMap == null) { - val properties = it.memberProperties - valueMap = ArrayMap(properties.size) - (properties as Collection>).forEach { property -> - property.isAccessible = true - valueMap[property.name] = property - } - injectMapCache[it] = valueMap as ArrayMap?> - } - valueMap.copy() - } - -private val T.injectMap: ArrayMap?> - @Suppress("UNCHECKED_CAST") - get() = (this::class as KClass).injectMap - -private val Array, Property?>>.injectMap get() = iterator().injectMap -private val Iterator, Property?>>.injectMap - get() = let { - val valueMap = ArrayMap?>() - @Suppress("UNCHECKED_CAST") - forEach { (k, field) -> - field?.isAccessible = true - valueMap[k.name] = field - } - //logger.trace("Iterator.injectMap: {}", valueMap) - valueMap - } - -private fun T.injectMap(clazz: KClass<*>?): ArrayMap?> = this::class - .cast>() - .injectMap - .also { - if (clazz == null) return@also - val clazzThis = this::class.java - - fun import(relation: Relation, property: Property) { - if (relation.clazz != clazz) return - //logger.trace("relation {} to {}", relation.property, property.name) - it[relation.property] = when { - relation.skip -> null - relation.handler.isEmpty() -> property - else -> try { - val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java) - handler.isAccessible = true - object : KMutableProperty1, KProperty1 by property { - override val setter: KMutableProperty1.Setter get() = TODO() - override fun set(receiver: T, value: Any?) = - handler(this@injectMap, value).inject(receiver, property) - } - } catch (e: Exception) { - //logger.warn("an exception caused on generate inject handler", e) - null - } - } - } - - fun parseAnnotation(annotation: Annotation, property: Property) { - when (annotation) { - is Relation -> import(annotation, property) - is Relations -> annotation.relations.forEach { relation -> import(relation, property) } - } - } - - this::class.memberProperties.cast>>().forEach { property -> - property.annotations.forEach { annotation -> parseAnnotation(annotation, property) } - (property.javaField ?: return@forEach).annotations.forEach { annotation -> - parseAnnotation(annotation, property) - } - } - } /** * 用于形式化的将List中的数据映射到实体类上 @@ -122,7 +34,7 @@ private fun T.injectMap(clazz: KClass<*>?): ArrayMap List.clone( unsafe: Boolean = true, - vararg relation: Pair, Property?> + vararg relation: Pair, Property?>, ): List { val list = ArrayList(size) val memberMap = T::class.injectMap @@ -131,25 +43,28 @@ inline fun List.clone( } forEach { it ?: return@forEach - val target = instance(unsafe) ?: return@forEach - list.add(it.inject(target, memberMap.iterator())) + try { + val target = InstantAllocator[T::class.java, unsafe] + list.add(it.inject(target, memberMap.iterator())) + } catch (e: Exception) { + } } return list } inline fun List.clone( unsafe: Boolean = true, - vararg relation: Property? -): T = clone(instance(unsafe)!!, relation.iterator()) + vararg relation: Property?, +): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator()) fun List.clone( target: T, - vararg relation: Property? + vararg relation: Property?, ): T = clone(target, relation.iterator()) fun List.clone( target: T, - relation: Iterator?> + relation: Iterator?>, ): T = relation.mapIndexed { index, kProperty1 -> (kProperty1 ?: return@mapIndexed null).name to this[index] }.clone(target) @@ -157,29 +72,30 @@ fun List.clone( /** * 新建并拷贝 + * @author 王景阔 * 创建类型 T 的实例 * 并将对象两个的所有同名字段拷贝进新建的实例中 * @return 新建的实例 * @param unsafe 是否允许使用 Unsafe 创建对象,unsafe 不需调用构造函数,可以在没有默认构造函数的情况下生成对象 */ -inline fun Any.clone(unsafe: Boolean = true): T = clone(instance(unsafe)!!) +inline fun Any.clone(unsafe: Boolean = true): T = clone(InstantAllocator[T::class.java, unsafe]) -fun Any.clone(clazz: Class, unsafe: Boolean = true): T = clone(instance(unsafe, clazz)!!) +fun Any.clone(clazz: Class, unsafe: Boolean = true): T = clone(InstantAllocator[clazz, unsafe]) @JvmName("unsafeClone") inline fun Any.clone( unsafe: Boolean = true, - vararg relation: Pair?> -): T = clone(instance(unsafe)!!, relation.iterator()) + vararg relation: Pair?>, +): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator()) inline fun S.clone( unsafe: Boolean = true, - vararg relation: Pair, Property?> -): T = clone(instance(unsafe)!!, relation.iterator()) + vararg relation: Pair, Property?>, +): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator()) fun Any.cloneMap(): Map = when (this) { - is Map<*, *> -> @Suppress("UNCHECKED_CAST") (this as Map).mapKeys { it.key.toString() } + is Map<*, *> -> uncheckedCast>().mapKeys { it.key.toString() } is Iterator<*> -> { val valueMap = HashMap() (this as Iterator).forEach { @@ -201,22 +117,22 @@ fun Any.clone(target: T): T = apply { injectWithoutProperty(target) }. fun S.clone( target: T, - iterator: Iterator, Property?>> + iterator: Iterator, Property?>>, ): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap - //.also { logger.trace("clone {} into {}, value map:{}", this, target, it) } + .also { logger.trace("clone {} into {}, value map:{}", this, target, it) } .clone(target, iterator.injectMap.iterator(), this::class) } fun Any.clone( target: T, - vararg relation: Pair?> + vararg relation: Pair?>, ): T = clone(target, relation.iterator()) @JvmName("unsafeClone") fun Any.clone( target: T, - iterator: Iterator?>> + iterator: Iterator?>>, ): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.clone(target, iterator, this::class) } @@ -225,9 +141,9 @@ fun Any.clone( fun Map.clone( target: T, iterator: Iterator?>>, - clazz: KClass<*>? = null + clazz: KClass<*>? = null, ): T { - val memberMap = target.injectMap(clazz) as MutableMap?> + val memberMap = target.injectMap(clazz) iterator.forEach { (k, v) -> memberMap[k] = v } @@ -238,9 +154,9 @@ fun Map.clone( fun Map.clone( target: T, iterator: Iterator, Property?>>, - clazz: KClass<*>? = null + clazz: KClass<*>? = null, ): T { - val memberMap = target.injectMap(clazz) as MutableMap?> + val memberMap = target.injectMap(clazz) iterator.forEach { (k, v) -> memberMap[k.get(target)?.toString() ?: return@forEach] = v } @@ -251,13 +167,13 @@ fun Map.clone( fun Map.clone( target: T, iterator: Iterator?>>, - clazz: KClass<*>? = null + clazz: KClass<*>? = null, ): T { val memberMap = target.injectMap(clazz) iterator.forEach { (k, v) -> memberMap[k ?: return@forEach] = v } - //logger.trace("inject {} into {}, mapping: {}", this, target, memberMap) + logger.trace("inject {} into {}, mapping: {}", this, target, memberMap) return inject(target, memberMap.iterator()) } @@ -268,229 +184,6 @@ fun Any.checkPropertyClone(target: T, ifClone: () -> T): T = target } -//fun Any.checkPropertyClone(targetClass: KClass, ifClone: () -> T): T { -// if (targetClass.findAnnotation()?.classList?.contains(this::class) != true) -// ifClone() -//} - -fun Any.injectWithoutProperty(target: T): T { - fun parseAnnotation(relation: Relation, property: KProperty1) { - if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try { - val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java) - handler.isAccessible = true - handler(target, this)?.inject(target, property) - } catch (e: Exception) { - //logger.warn("an exception caused on global inject", e) - } - } - - target::class.memberProperties - .cast>>() - .forEach { property -> - property.annotations.forEach { annotation -> - when (annotation) { - is Relation -> parseAnnotation(annotation, property) - is Relations -> annotation.relations.forEach { parseAnnotation(it, property) } - } - } - property.javaField?.annotations?.forEach { annotation -> - when (annotation) { - is Relation -> parseAnnotation(annotation, property) - is Relations -> annotation.relations.forEach { parseAnnotation(it, property) } - } - } - } - return target -} - -fun Any.inject( - target: T, - iterator: Iterator?>> -): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) } - -@JvmName("injectMap") -fun Any.inject( - target: T, - iterator: Iterator?>> -): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) } - -fun Map.inject( - target: T, - iterator: Iterator?>> -): T { - iterator.forEach { (k, t) -> - val value = this[k] ?: return@forEach - value.inject(target, t ?: return@forEach) - } - return target -} - -fun Map.p2pInject( - target: T, - iterator: Iterator, Property?>> -): T { - iterator.forEach { (k, t) -> - val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach - value.inject(target, t ?: return@forEach) - } - return target -} - -@JvmName("injectMap") -fun Map.inject( - target: T, - iterator: Iterator?>> -): T { - iterator.forEach { (k, t) -> - val value = this[k] ?: return@forEach - value.inject(target, t ?: return@forEach) - } - return target -} - -fun Any.inject(target: T, property: Property) { - //logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name) - when (property) { - is KMutableProperty1<*, *> -> { - @Suppress("UNCHECKED_CAST") - property as KMutableProperty1 - property.isAccessible = true - try { - property.set(target, cast(this, property.returnType.javaType.cast()) ?: return) - } catch (e: ClassCastException) { - //logger.trace("inject failed", e) - } - } - else -> { - val field = property.javaField ?: return - field.isAccessible = true - field.final = false - try { - field.set(target, cast(this, field.type) ?: return) - } catch (e: Exception) { - //logger.trace("inject failed", e) - } - } - } -} - -fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) { - source -} else when (target) { - Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull() - Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar() - Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull() - Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull() - Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull() - Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull() - Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull() - Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean() - - java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull() - java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull() - ?.toChar() - java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull() - java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull() - java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull() - java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull() - java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull() - java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean() - - String::class.java -> source.toString() - - else -> source -} - -fun T.read(source: Any?): T = source?.clone(this) ?: this - -fun T.read( - source: S?, - vararg relation: Pair, Property?> -): T = source?.clone(this, relation.iterator()) ?: this - -fun T.read( - source: Map?, - vararg relation: Pair?> -): T = source?.clone(this, relation.iterator()) ?: this - - -fun T.p2pRead( - source: Map?, - vararg relation: Pair, Property?> -): T { - //logger.trace("p2p read, source:{}, relation: {}", source, relation) - return source?.p2pInject(this, relation.iterator()) ?: this -} - -fun T.p2pRead( - source: Map? -): T { - source ?: return this - val properties = this::class.memberProperties.cast>>() - val relation = properties.mapNotNull { property -> - val key = property.javaField?.getAnnotation(Key::class.java)?.key ?: return@mapNotNull null - val keyProperty = properties.find { it.name == key } ?: return@mapNotNull null - keyProperty to property - } - //logger.trace("p2p read, source:{}, relation: {}", source, relation) - return source.p2pInject(this, relation.iterator()) -} - -fun T.p2pRead( - source: Any? -): T { - source ?: return this - val properties = this::class.memberProperties.cast>>() - properties.forEach { property -> - val keyAnnotation = property.javaField?.getAnnotation(Key::class.java) ?: return@forEach - if (keyAnnotation.handler.isEmpty()) return@forEach - if (keyAnnotation.clazz.isInstance(source).not()) return@forEach - val handler = this::class.java.getDeclaredMethod(keyAnnotation.handler, keyAnnotation.clazz.java) - (handler(this, source) ?: return@forEach).inject(this, property) - } - return this -} - -fun List.read( - source: List, - vararg relation: Pair, Property?> -): List { - val memberMap = this[0].injectMap as MutableMap?> - relation.forEach { (k, v) -> - memberMap[k.name] = v - } - return source.mapIndexed { index, it -> it.inject(this[index], memberMap.iterator()) } -} - -inline fun read(vararg values: Any, unsafe: Boolean = true): T { - val instance = instance(unsafe)!! - values.forEach { - it.clone(instance) - } - return instance -} - -inline fun read(value: Any, unsafe: Boolean = true): T = value.clone(unsafe) - -fun T.readWithoutProperty(vararg values: Any): T { - values.forEach { - it.injectWithoutProperty(this) - } - return this -} - -inline fun instance(unsafe: Boolean = true) = instance(unsafe, T::class.java) - -fun instance(unsafe: Boolean = true, clazz: Class): T? = try { - clazz.newInstance()!! -} catch (e: Exception) { - if (unsafe) { - @Suppress("UNCHECKED_CAST") - Unsafe.unsafe.allocateInstance(clazz) as T? - } else { - null - } -} inline fun , V> Iterator.mapIndexed(action: (Int, T) -> Pair?): Map { val map = ArrayMap() @@ -502,6 +195,113 @@ inline fun , V> Iterator.mapIndexed(action: (Int, T) -> return map } -fun T.mapRead(map: Map, key: KProperty1): T { - return read(map[key.get(this)?.toString() ?: return this] ?: return this) +fun T.set(field: KProperty1, value: F): T { + (value as Any?)?.inject(this, field as Property) + return this +} + +fun T.deepClone(): T = when (this) { + is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this + is CharArray -> copyOf().uncheckedCast() + is BooleanArray -> copyOf().uncheckedCast() + is ByteArray -> copyOf().uncheckedCast() + is ShortArray -> copyOf().uncheckedCast() + is IntArray -> copyOf().uncheckedCast() + is LongArray -> copyOf().uncheckedCast() + is FloatArray -> copyOf().uncheckedCast() + is DoubleArray -> copyOf().uncheckedCast() + else -> deepClone(HashMap()) +} + +private fun T.deepClone(clonedMap: MutableMap): T = + clonedMap[this]?.uncheckedCast() ?: when (this) { + is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this + is CharArray -> copyOf().uncheckedCast() + is BooleanArray -> copyOf().uncheckedCast() + is ByteArray -> copyOf().uncheckedCast() + is ShortArray -> copyOf().uncheckedCast() + is IntArray -> copyOf().uncheckedCast() + is LongArray -> copyOf().uncheckedCast() + is FloatArray -> copyOf().uncheckedCast() + is DoubleArray -> copyOf().uncheckedCast() + is Array<*> -> { + val instance = java.lang.reflect.Array.newInstance(javaClass.componentType, size).uncheckedCast>() + forEachIndexed { index, it -> + instance[index] = it?.deepClone(clonedMap) + } + instance.uncheckedCast() + } + else -> { + val clazz = javaClass + val newInstance = unsafeInstance(clazz)!! + clonedMap[this] = newInstance + clazz.forAllFields { field -> + if (field.isStatic()) return@forAllFields + field.isAccessible = true + field.set(newInstance, field.get(this)?.deepClone(clonedMap)) + } + newInstance + } + } + +fun Any?.details(name: String = "", skipStatic: Boolean = true) = buildString { + this@details.details(HashMap(), this, "", name, skipStatic) +} + +private fun Any?.details( + map: MutableMap, + builder: StringBuilder, + indentation: String, + name: String = "", + skipStatic: Boolean = true, + directValue: String = "|- ", + objectValue: String = "/- ", + hint: String = "${TextColor.red}|${TextColor.reset} ", + tmpIndentation: String = "", + type: String? = null, +) { + when (this) { + null, is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*>, is String -> + builder.append("$indentation$tmpIndentation$directValue$name(${type ?: this?.javaClass?.name ?: "null"}): $this\n") + is CharArray -> builder.append("$indentation$tmpIndentation$directValue$name(CharArray): ${String(this)}\n") + is BooleanArray -> builder.append("$indentation$tmpIndentation$directValue$name(BooleanArray): ${asList()}\n") + is ByteArray -> builder.append("$indentation$tmpIndentation$directValue$name(ByteArray): 0x${toHexString()}\n") + is ShortArray -> builder.append("$indentation$tmpIndentation$directValue$name(ShortArray): ${asList()}\n") + is IntArray -> builder.append("$indentation$tmpIndentation$directValue$name(IntArray): ${asList()}\n") + is LongArray -> builder.append("$indentation$tmpIndentation$directValue$name(LongArray): ${asList()}\n") + is FloatArray -> builder.append("$indentation$tmpIndentation$directValue$name(FloatArray): ${asList()}\n") + is DoubleArray -> builder.append("$indentation$tmpIndentation$directValue$name(DoubleArray): ${asList()}\n") + is Array<*> -> { + builder.append("$indentation$tmpIndentation$objectValue$name: (Array<${javaClass.componentType.name}>, ${hashCode()})\n") + if (this !in map) { + map[this] = hashCode() + val newIndentation = "$indentation$hint" + forEachIndexed { index, it -> + val newTmpIndentation = "|- ${name.ifEmpty { "array" }}[$index]" + it.details( + map, builder, newIndentation, + skipStatic = skipStatic, + directValue = " = ", + objectValue = " = /- ", + hint = "${TextColor.red}|${TextColor.reset} ${" ".repeat(newTmpIndentation.length + 1)}${TextColor.red}|${TextColor.reset} ", + tmpIndentation = newTmpIndentation + ) + } + } + } + in map -> builder.append("$indentation$tmpIndentation$directValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${map[this]}, generated)\n") + else -> { + map[this] = this.hashCode() + builder.append("$indentation$tmpIndentation$objectValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${hashCode()})\n") + val newIndentation = "$indentation$hint" + javaClass.forAllFields { field -> + if (skipStatic && field.isStatic()) { + return@forAllFields + } + field.isAccessible = true + val value = field.get(this) + value.details(map, builder, newIndentation, field.name, skipStatic, type = field.type.name) + } + } + } } \ No newline at end of file diff --git a/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/cloneBackend.kt b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/cloneBackend.kt new file mode 100644 index 0000000..d36aa9a --- /dev/null +++ b/ts-core/ts-clone/src/main/kotlin/cn/tursom/core/clone/cloneBackend.kt @@ -0,0 +1,267 @@ +package cn.tursom.core.clone + +import cn.tursom.core.* +import cn.tursom.core.datastruct.KPropertyValueMap +import cn.tursom.core.datastruct.SoftArrayMap +import cn.tursom.log.impl.Slf4jImpl +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set +import kotlin.reflect.* +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.isAccessible +import kotlin.reflect.jvm.javaField +import kotlin.reflect.jvm.javaType + +private val logger = Slf4jImpl().logger + +val Any.valueMap: Map + get() = if (this is Map<*, *>) { + uncheckedCast() + } else { + KPropertyValueMap(this) + } + +private val injectMapCache = SoftArrayMap, Map?>>(ConcurrentHashMap()) + +val KClass.injectMap: MutableMap?> + @Suppress("UNCHECKED_CAST") + get() { + var injectMap = injectMapCache[this] as Map?>? + if (injectMap == null) { + injectMap = allMemberProperties.associateByTo(HashMap()) { property -> + property.isAccessible = true + property.name + } + injectMapCache[this] = injectMap as Map?> + } + return HashMap(injectMap) + } + +internal val T.injectMap: MutableMap?> + get() = this::class.uncheckedCast>().injectMap + +internal val Iterator, Property?>>.injectMap + get() = let { + val valueMap = HashMap?>() + @Suppress("UNCHECKED_CAST") + forEach { (k, field) -> + field?.isAccessible = true + valueMap[k.name] = field + } + logger.trace("Iterator.injectMap: {}", valueMap) + valueMap + } + +internal fun T.injectMap(targetClazz: KClass<*>?): MutableMap?> = this::class + .uncheckedCast>() + .injectMap + .also { injectMap -> + if (targetClazz == null) return@also + val clazzThis = this::class.java + + fun import(relation: Relation, property: Property) { + if (relation.clazz != targetClazz) return + var propertyName = relation.property + if (propertyName.isBlank()) { + propertyName = property.name + } + logger.trace("relation {} to {}", propertyName, property.name) + injectMap[propertyName] = when { + relation.skip -> null + relation.handler.isEmpty() -> property + else -> try { + val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java) + handler.isAccessible = true + object : KMutableProperty1, KProperty1 by property { + override val setter: KMutableProperty1.Setter + get() = object : KMutableProperty1.Setter, KCallable by property.uncheckedCast() { + override val isExternal: Boolean get() = false + override val isInfix: Boolean get() = false + override val isInline: Boolean get() = false + override val isOperator: Boolean get() = false + override val isSuspend: Boolean get() = false + override val property: KProperty get() = property + override fun invoke(receiver: T, value: Any?) = + handler(this@injectMap, value).inject(receiver, property) + } + + override fun set(receiver: T, value: Any?) = try { + handler(this@injectMap, value).inject(receiver, property) + } catch (e: Exception) { + logger.trace("", e) + } + } + } catch (e: Exception) { + logger.warn("an exception caused on generate inject handler", e) + null + } + } + } + + fun parseAnnotation(annotation: Annotation, property: Property) { + when (annotation) { + is Relation -> import(annotation, property) + is Relations -> annotation.relations.forEach { relation -> import(relation, property) } + } + } + + this::class.memberProperties.uncheckedCast>>().forEach { property -> + property.annotations.forEach { annotation -> parseAnnotation(annotation, property) } + (property.javaField ?: return@forEach).annotations.forEach { annotation -> + parseAnnotation(annotation, property) + } + } + } + +fun Any.injectWithoutProperty(target: T): T { + fun parseAnnotation(relation: Relation, property: KProperty1) { + if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try { + val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java) + handler.isAccessible = true + handler(target, this)?.inject(target, property) + } catch (e: Exception) { + logger.trace("an exception caused on global inject", e) + } + } + + target::class.memberProperties + .uncheckedCast>>() + .forEach { property -> + property.annotations.forEach { annotation -> + when (annotation) { + is Relation -> parseAnnotation(annotation, property) + is Relations -> annotation.relations.forEach { parseAnnotation(it, property) } + } + } + property.javaField?.annotations?.forEach { annotation -> + when (annotation) { + is Relation -> parseAnnotation(annotation, property) + is Relations -> annotation.relations.forEach { parseAnnotation(it, property) } + } + } + } + return target +} + +fun Any.inject( + target: T, + iterator: Iterator?>>, +): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) } + +@JvmName("injectMap") +fun Any.inject( + target: T, + iterator: Iterator?>>, +): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) } + +fun Map.inject( + target: T, + iterator: Iterator?>>, +): T { + iterator.forEach { (k, t) -> + val value = this[k] ?: return@forEach + value.inject(target, t ?: return@forEach) + } + return target +} + +/** + * point to point inject + * 通过指定映射关系,从本map中取出数据并注入到目标对象中 + * + */ +fun Map.p2pInject( + target: T, + iterator: Iterator, Property?>>, +): T { + iterator.forEach { (k, t) -> + val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach + value.inject(target, t ?: return@forEach) + } + return target +} + +@JvmName("injectMap") +fun Map.inject( + target: T, + iterator: Iterator?>>, +): T { + iterator.forEach { (k, t) -> + val value = this[k] ?: return@forEach + value.inject(target, t ?: return@forEach) + } + return target +} + +fun Any.inject(target: T, property: Property) { + logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name) + when (property) { + is KMutableProperty1<*, *> -> { + @Suppress("UNCHECKED_CAST") + property as KMutableProperty1 + property.isAccessible = true + try { + property.set(target, cast(this, property.returnType.javaType.uncheckedCast()) ?: return) + } catch (e: ClassCastException) { + if (logger.isTraceEnabled) { + logger.trace("inject {} failed", property.name, e) + } + } catch (e: Exception) { + logger.error("inject {} failed", property.name, e) + } + } + else -> { + val field = property.javaField ?: return + field.isAccessible = true + try { + field.set(target, cast(this, field.type) ?: return) + } catch (e: ClassCastException) { + if (logger.isTraceEnabled) { + logger.trace("inject {} failed", property.name, e) + } + } catch (e: Exception) { + logger.error("inject {} failed", property.name, e) + } + } + } +} + +fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) { + source +} else when (target) { + Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull() + Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar() + Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull() + Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull() + Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull() + Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull() + Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull() + Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean() + + java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull() + java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull() + ?.toChar() + java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull() + java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull() + java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull() + java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull() + java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull() + java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean() + + String::class.java -> source.toString() + + else -> source +} + +inline fun instance(unsafe: Boolean = true) = instance(unsafe, T::class.java) + +fun instance(unsafe: Boolean = true, clazz: Class): T = InstantAllocator[clazz, unsafe] + +fun unsafeInstance(clazz: Class, unsafe: Boolean = true): T? = if (unsafe) { + @Suppress("UNCHECKED_CAST") + Unsafe.unsafe.allocateInstance(clazz) as T? +} else { + null +} \ No newline at end of file diff --git a/ts-core/ts-coroutine/build.gradle.kts b/ts-core/ts-coroutine/build.gradle.kts index 1b0fb84..6d3449a 100644 --- a/ts-core/ts-coroutine/build.gradle.kts +++ b/ts-core/ts-coroutine/build.gradle.kts @@ -24,7 +24,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-coroutine/ts-coroutine-lock/build.gradle.kts b/ts-core/ts-coroutine/ts-coroutine-lock/build.gradle.kts index 4602613..6d3449a 100644 --- a/ts-core/ts-coroutine/ts-coroutine-lock/build.gradle.kts +++ b/ts-core/ts-coroutine/ts-coroutine-lock/build.gradle.kts @@ -5,6 +5,7 @@ plugins { dependencies { implementation(project(":ts-core")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2") } @kotlin.Suppress("UNCHECKED_CAST") @@ -23,7 +24,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-datastruct/build.gradle.kts b/ts-core/ts-datastruct/build.gradle.kts index c4892e9..abfea12 100644 --- a/ts-core/ts-datastruct/build.gradle.kts +++ b/ts-core/ts-datastruct/build.gradle.kts @@ -26,7 +26,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ArrayMap.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ArrayMap.kt index aa529c8..47e6a7b 100644 --- a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ArrayMap.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ArrayMap.kt @@ -1,6 +1,6 @@ package cn.tursom.core.datastruct -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast @Suppress("MemberVisibilityCanBePrivate") open class ArrayMap(initialCapacity: Int = 16) : SimpMap { @@ -149,7 +149,7 @@ open class ArrayMap(initialCapacity: Int = 16) : SimpMap { override fun setValue(newValue: V): V = value.also { value = newValue } override fun compareTo(other: K): Int { return if (key is Comparable<*>) { - key.cast>().compareTo(other) + key.uncheckedCast>().compareTo(other) } else { -1 } diff --git a/utils/src/main/kotlin/cn/tursom/utils/AsyncIterator.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/AsyncIterator.kt similarity index 91% rename from utils/src/main/kotlin/cn/tursom/utils/AsyncIterator.kt rename to ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/AsyncIterator.kt index 99bc7c6..4a3414e 100644 --- a/utils/src/main/kotlin/cn/tursom/utils/AsyncIterator.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/AsyncIterator.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils +package cn.tursom.core.datastruct interface AsyncIterator { /** diff --git a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMap.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMap.kt index 1a9b6ad..9672873 100644 --- a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMap.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMap.kt @@ -1,11 +1,11 @@ package cn.tursom.core.datastruct -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast class DefaultValueMap( private val map: Map, - private val defaultValue: (K) -> V -) : Map by map.cast() { + private val defaultValue: (K) -> V, +) : Map by map.uncheckedCast() { override val entries: Set> get() = Entry() override val values: Collection get() = Values() @@ -21,8 +21,8 @@ class DefaultValueMap( } inner class Entry( - private val entries: Set> = map.entries - ) : Set> by entries.cast() { + private val entries: Set> = map.entries, + ) : Set> by entries.uncheckedCast() { override val size: Int get() = entries.count { it.value != null } override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null override fun iterator(): Iterator> = EntryIterator() @@ -32,7 +32,7 @@ class DefaultValueMap( private var next: Map.Entry? = null override fun hasNext(): Boolean { while (iterator.hasNext()) { - next = iterator.next().cast() + next = iterator.next().uncheckedCast() if (next?.value != null) { return true } @@ -44,13 +44,13 @@ class DefaultValueMap( next != null -> next hasNext() -> next else -> throw NoSuchElementException() - }.cast() + }.uncheckedCast() } } inner class Values( - private val values: Collection = map.values - ) : Collection by values.cast() { + private val values: Collection = map.values, + ) : Collection by values.uncheckedCast() { override val size: Int get() = values.count { it != null } override fun isEmpty(): Boolean = values.first { it != null } == null override fun iterator(): Iterator = ValuesIterator() @@ -61,7 +61,7 @@ class DefaultValueMap( override fun hasNext(): Boolean { while (iterator.hasNext()) { - next = iterator.next().cast() + next = iterator.next().uncheckedCast() if (next != null) { return true } @@ -73,7 +73,7 @@ class DefaultValueMap( next != null -> next hasNext() -> next else -> throw NoSuchElementException() - }.cast() + }.uncheckedCast() } } } diff --git a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMutableMap.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMutableMap.kt index 456f610..adc74cc 100644 --- a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMutableMap.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/DefaultValueMutableMap.kt @@ -1,11 +1,11 @@ package cn.tursom.core.datastruct -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast class DefaultValueMutableMap( private val map: MutableMap, - private val defaultValue: (K) -> V -) : MutableMap by map.cast() { + private val defaultValue: (K) -> V, +) : MutableMap by map.uncheckedCast() { override val entries: MutableSet> get() = Entry() override val values: MutableCollection get() = Values() @@ -19,19 +19,19 @@ class DefaultValueMutableMap( } inner class Entry( - private val entries: MutableSet> = map.entries - ) : MutableSet> by entries.cast() { + private val entries: MutableSet> = map.entries, + ) : MutableSet> by entries.uncheckedCast() { override val size: Int get() = entries.count { it.value != null } override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null override fun iterator(): MutableIterator> = EntryIterator() inner class EntryIterator( - private val iterator: MutableIterator> = entries.iterator() - ) : MutableIterator> by iterator.cast() { + private val iterator: MutableIterator> = entries.iterator(), + ) : MutableIterator> by iterator.uncheckedCast() { private var next: Map.Entry? = null override fun hasNext(): Boolean { while (iterator.hasNext()) { - next = iterator.next().cast() + next = iterator.next().uncheckedCast() if (next?.value != null) { return true } @@ -43,25 +43,25 @@ class DefaultValueMutableMap( next != null -> next hasNext() -> next else -> throw NoSuchElementException() - }.cast() + }.uncheckedCast() } } inner class Values( - private val values: MutableCollection = map.values - ) : MutableCollection by values.cast() { + private val values: MutableCollection = map.values, + ) : MutableCollection by values.uncheckedCast() { override val size: Int get() = values.count { it != null } override fun isEmpty(): Boolean = values.first { it != null } == null override fun iterator(): MutableIterator = ValuesIterator() inner class ValuesIterator( - private val iterator: MutableIterator = values.iterator() - ) : MutableIterator by iterator.cast() { + private val iterator: MutableIterator = values.iterator(), + ) : MutableIterator by iterator.uncheckedCast() { private var next: V? = null override fun hasNext(): Boolean { while (iterator.hasNext()) { - next = iterator.next().cast() + next = iterator.next().uncheckedCast() if (next != null) { return true } @@ -73,7 +73,7 @@ class DefaultValueMutableMap( next != null -> next hasNext() -> next else -> throw NoSuchElementException() - }.cast() + }.uncheckedCast() } } } \ No newline at end of file diff --git a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/KPropertyValueMap.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/KPropertyValueMap.kt index 7d64468..03e0d93 100644 --- a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/KPropertyValueMap.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/KPropertyValueMap.kt @@ -1,6 +1,6 @@ package cn.tursom.core.datastruct -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast import kotlin.reflect.KClass import kotlin.reflect.KProperty1 import kotlin.reflect.full.memberProperties @@ -23,7 +23,7 @@ class KPropertyValueMap(val target: Any) : Map { operator fun get(clazz: KClass<*>): SoftArrayMap> { var map = propertiesMapCache[clazz] if (map == null) { - map = clazz.memberProperties.cast>>().let { properties -> + map = clazz.memberProperties.uncheckedCast>>().let { properties -> val valueMap = SoftArrayMap>(properties.size) properties.forEach { it.isAccessible = true diff --git a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt index 029b6b3..2675c08 100644 --- a/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt +++ b/ts-core/ts-datastruct/src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt @@ -1,6 +1,6 @@ package cn.tursom.core.datastruct -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast @Suppress("MemberVisibilityCanBePrivate") open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { @@ -17,8 +17,8 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { @Suppress("LeakingThis") override val entries: MutableSet> = EntrySet(this) - override val keys: MutableSet get() = arrValue.asList().subList(0, end).toMutableSet().cast() - override val values: MutableCollection get() = arrValue.asList().cast>().subList(0, end) + override val keys: MutableSet get() = arrValue.asList().subList(0, end).toMutableSet().uncheckedCast() + override val values: MutableCollection get() = arrValue.asList().uncheckedCast>().subList(0, end) /** * @param key 查找的键 @@ -59,7 +59,7 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { fun setByIndex(index: Int, value: V): V? { val oldValue = arrValue[end] arrValue[index] = value - return oldValue.cast() + return oldValue.uncheckedCast() } override fun delete(key: K): V? { @@ -72,7 +72,7 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { System.arraycopy(arr, index + 1, arr, index, end - index - 1) System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1) end-- - return oldValue.cast() + return oldValue.uncheckedCast() } override fun clear() { @@ -83,7 +83,7 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { return if (end <= 0) { null } else { - arrValue[0].cast() + arrValue[0].uncheckedCast() } } @@ -109,7 +109,7 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { return if (index < 0 || index >= end) { null } else { - arr[index].cast() + arr[index].uncheckedCast() } } @@ -117,7 +117,7 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { return if (index < 0 || index >= end) { null } else { - arrValue[index].cast() + arrValue[index].uncheckedCast() } } @@ -194,10 +194,10 @@ open class ParallelArrayMap(initialCapacity: Int = 16) : SimpMap { val map: ParallelArrayMap, val index: Int ) : MutableMap.MutableEntry { - override val key: K get() = map.getKeyByIndex(index).cast() - override val value: V get() = map.getByIndex(index).cast() + override val key: K get() = map.getKeyByIndex(index).uncheckedCast() + override val value: V get() = map.getByIndex(index).uncheckedCast() override fun setValue(newValue: V): V { - return map.setByIndex(index, newValue).cast() + return map.setByIndex(index, newValue).uncheckedCast() } } } diff --git a/ts-core/ts-delegation/build.gradle.kts b/ts-core/ts-delegation/build.gradle.kts index 5da66a7..47ef1dc 100644 --- a/ts-core/ts-delegation/build.gradle.kts +++ b/ts-core/ts-delegation/build.gradle.kts @@ -23,7 +23,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/AutoUpdatableMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/AutoUpdatableMutableDelegatedField.kt new file mode 100644 index 0000000..8df3e23 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/AutoUpdatableMutableDelegatedField.kt @@ -0,0 +1,29 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.uncheckedCast +import kotlin.reflect.KProperty + +/** + * 当从上一级 MutableDelegatedField 获得到空值时 + * 自动调用updateValue方法更新值 + */ +class AutoUpdatableMutableDelegatedField( + override val delegatedField: MutableDelegatedField, + val updateValue: T.(property: KProperty<*>) -> V, +) : MutableDelegatedField by delegatedField.uncheckedCast(), + DecoratorMutableDelegatedField { + override fun getValue(thisRef: T, property: KProperty<*>): V { + var value = delegatedField.getValue(thisRef, property) + if (value == null) { + value = thisRef.updateValue(property) + delegatedField.setValue(thisRef, property, value) + } + return value + } +} + +fun MutableDelegatedField.autoUpdate( + updateValue: T.(property: KProperty<*>) -> V, +): MutableDelegatedField { + return AutoUpdatableMutableDelegatedField(this, updateValue) +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegateProvider.kt similarity index 51% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegateProvider.kt index aebbc6c..86fd38a 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegateProvider.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegateProvider.kt @@ -1,9 +1,12 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty interface DecoratorDelegateProvider : DelegateProvider>, DecoratorDelegatedField { - override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): DelegatedField = delegatedField + override operator fun provideDelegate( + thisRef: T, + prop: KProperty<*>, + ): DelegatedField = delegatedField } \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegatedField.kt similarity index 73% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegatedField.kt index e007cae..94167d9 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation interface DecoratorDelegatedField { val delegatedField: DelegatedField diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegateProvider.kt similarity index 85% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegateProvider.kt index d0c44ea..4fc4892 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegateProvider.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegateProvider.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty @@ -7,5 +7,5 @@ interface DecoratorMutableDelegateProvider : //DecoratorProvideDelegate, DecoratorMutableDelegatedField { override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): MutableDelegatedField = - mutableDelegatedField + delegatedField } diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegatedField.kt new file mode 100644 index 0000000..1160617 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DecoratorMutableDelegatedField.kt @@ -0,0 +1,5 @@ +package cn.tursom.core.delegation + +interface DecoratorMutableDelegatedField : DecoratorDelegatedField { + override val delegatedField: MutableDelegatedField +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegateProvider.kt similarity index 80% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegateProvider.kt index d737a49..945e0db 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegateProvider.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegateProvider.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt similarity index 97% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt index c59cf69..b736d6e 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedFieldAttachmentKey.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedFieldAttachmentKey.kt new file mode 100644 index 0000000..4654c65 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/DelegatedFieldAttachmentKey.kt @@ -0,0 +1,8 @@ +package cn.tursom.core.delegation + +import kotlin.reflect.KProperty0 + +interface DelegatedFieldAttachmentKey { + operator fun get(delegatedField: DelegatedField<*, *>) = delegatedField[this] + operator fun get(property0: KProperty0<*>) = property0.getDelegatedAttachmentValue(this) +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExecutorMutableDelegatedField.kt similarity index 56% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExecutorMutableDelegatedField.kt index d1f2366..8b6053c 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ExecutorMutableDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExecutorMutableDelegatedField.kt @@ -1,20 +1,20 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import java.util.concurrent.Executor import kotlin.reflect.KProperty class ExecutorMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, + override val delegatedField: MutableDelegatedField, private val executor: Executor, -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { executor.execute { - mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + delegatedField.valueOnSet(thisRef, property, value, oldValue) } } override fun setValue(thisRef: T, property: KProperty<*>, value: V) { valueOnSet(thisRef, property, value, getValue()) - mutableDelegatedField.setValue(value) + delegatedField.setValue(value) } } diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExpirableMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExpirableMutableDelegatedField.kt new file mode 100644 index 0000000..9787123 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ExpirableMutableDelegatedField.kt @@ -0,0 +1,46 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.uncheckedCast +import java.util.concurrent.TimeUnit +import kotlin.reflect.KProperty + +class ExpirableMutableDelegatedField( + override val delegatedField: MutableDelegatedField, + val expireMS: Long, +) : MutableDelegatedField by delegatedField.uncheckedCast(), + DecoratorMutableDelegatedField { + + @Volatile + private var setTime: Long = 0L + + override fun getValue(thisRef: T, property: KProperty<*>): V? { + return if (System.currentTimeMillis() - setTime < expireMS) { + delegatedField.uncheckedCast>().getValue(thisRef, property) + } else { + null + } + } + + override fun setValue(thisRef: T, property: KProperty<*>, value: V?) { + if (value != null) { + delegatedField.setValue(value) + setTime = System.currentTimeMillis() + } + } +} + +fun MutableDelegatedField.expirable( + expireTime: Long, + timeUnit: TimeUnit = TimeUnit.MILLISECONDS, +): MutableDelegatedField { + return ExpirableMutableDelegatedField(this, timeUnit.toMillis(expireTime)) +} + +@JvmName("expirableTV?") +fun MutableDelegatedField.expirable( + expireTime: Long, + timeUnit: TimeUnit = TimeUnit.MILLISECONDS, +): MutableDelegatedField { + return ExpirableMutableDelegatedField(uncheckedCast(), timeUnit.toMillis(expireTime)) +} + diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/FilterDelegatedField.kt similarity index 60% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/FilterDelegatedField.kt index 4a82cc6..2ef9833 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/FilterDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/FilterDelegatedField.kt @@ -1,18 +1,18 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation -import cn.tursom.core.cast +import cn.tursom.core.uncheckedCast import kotlin.reflect.KProperty class FilterDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, + override val delegatedField: MutableDelegatedField, private val filter: T.(old: V, new: V) -> Boolean, -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { companion object Key : DelegatedFieldAttachmentKey private var filterResult = false override fun get(key: DelegatedFieldAttachmentKey): K? { - return if (key == Key) filterResult.cast() else super.get(key) + return if (key == Key) filterResult.uncheckedCast() else super.get(key) } override fun setValue(thisRef: T, property: KProperty<*>, value: V) { @@ -20,7 +20,7 @@ class FilterDelegatedField( if (!filterResult) { return } - mutableDelegatedField.setValue(thisRef, property, value) + delegatedField.setValue(thisRef, property, value) } override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { @@ -28,6 +28,6 @@ class FilterDelegatedField( if (!filterResult) { return } - mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + delegatedField.valueOnSet(thisRef, property, value, oldValue) } } \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterDelegatedField.kt similarity index 92% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterDelegatedField.kt index 86b205d..5d94c33 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterMutableDelegatedField.kt new file mode 100644 index 0000000..f15ae95 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/GetterMutableDelegatedField.kt @@ -0,0 +1,10 @@ +package cn.tursom.core.delegation + +import kotlin.reflect.KProperty + +class GetterMutableDelegatedField( + override val delegatedField: MutableDelegatedField, + private val getter: MutableDelegatedField.(thisRef: T, property: KProperty<*>) -> V, +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { + override fun getValue(thisRef: T, property: KProperty<*>): V = delegatedField.getter(thisRef, property) +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyDelegatedField.kt similarity index 84% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyDelegatedField.kt index 2ab2d7b..1960a89 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty0 diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyMutableDelegatedField.kt similarity index 88% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyMutableDelegatedField.kt index 168d5ca..0c364cd 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/KPropertyMutableDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/KPropertyMutableDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KMutableProperty0 diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/LockMutableDelegatedField.kt similarity index 63% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/LockMutableDelegatedField.kt index 76c2924..7b97c3a 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/LockMutableDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/LockMutableDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock @@ -6,23 +6,23 @@ import kotlin.concurrent.withLock import kotlin.reflect.KProperty class LockMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, + override val delegatedField: MutableDelegatedField, private val lock: Lock = ReentrantLock(), -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { constructor( initValue: V, lock: Lock = ReentrantLock(), ) : this(MutableDelegatedFieldValue(initValue), lock) override fun getValue(thisRef: T, property: KProperty<*>): V = lock.withLock { - mutableDelegatedField.getValue(thisRef, property) + delegatedField.getValue(thisRef, property) } override fun setValue(thisRef: T, property: KProperty<*>, value: V) = lock.withLock { - mutableDelegatedField.setValue(thisRef, property, value) + delegatedField.setValue(thisRef, property, value) } override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) = lock.withLock { - mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + delegatedField.valueOnSet(thisRef, property, value, oldValue) } } \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedField.kt similarity index 94% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedField.kt index fd4f19e..d998c9a 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedFieldValue.kt similarity index 86% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedFieldValue.kt index c2aca26..8e29d30 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/MutableDelegatedFieldValue.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/MutableDelegatedFieldValue.kt @@ -1,9 +1,9 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import kotlin.reflect.KProperty open class MutableDelegatedFieldValue( - private var initValue: V + private var initValue: V, ) : MutableDelegatedField { override fun getValue(): V = initValue override fun getValue(thisRef: T, property: KProperty<*>): V = initValue diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullDelegatedField.kt new file mode 100644 index 0000000..ab767c8 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullDelegatedField.kt @@ -0,0 +1,27 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.uncheckedCast +import kotlin.reflect.KProperty + +class NotNullDelegatedField( + override val delegatedField: DelegatedField, + val ifNull: () -> Nothing = { throw NullPointerException() }, +) : DelegatedField by delegatedField.uncheckedCast(), DecoratorDelegatedField { + override fun getValue(): V { + val value = delegatedField.getValue() + if (value == null) { + ifNull() + } else { + return value + } + } + + override fun getValue(thisRef: T, property: KProperty<*>): V { + val value = delegatedField.getValue(thisRef, property) + if (value == null) { + ifNull() + } else { + return value + } + } +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullMutableDelegatedField.kt new file mode 100644 index 0000000..b9b5c47 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/NotNullMutableDelegatedField.kt @@ -0,0 +1,28 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.uncheckedCast +import kotlin.reflect.KProperty + +class NotNullMutableDelegatedField( + override val delegatedField: MutableDelegatedField, + val ifNull: () -> Nothing = { throw NullPointerException() }, +) : MutableDelegatedField by delegatedField.uncheckedCast(), DecoratorMutableDelegatedField { + override fun getValue(): V { + val value = delegatedField.getValue() + if (value == null) { + ifNull() + } else { + return value + } + } + + override fun getValue(thisRef: T, property: KProperty<*>): V { + val value = delegatedField.getValue(thisRef, property) + if (value == null) { + ifNull() + } else { + return value + } + } +} + diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReadWriteLockMutableDelegatedField.kt similarity index 67% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReadWriteLockMutableDelegatedField.kt index 4f2d2ee..c70b6df 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ReadWriteLockMutableDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReadWriteLockMutableDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation import java.util.concurrent.locks.ReadWriteLock import java.util.concurrent.locks.ReentrantReadWriteLock @@ -7,9 +7,9 @@ import kotlin.concurrent.write import kotlin.reflect.KProperty class ReadWriteLockMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, + override val delegatedField: MutableDelegatedField, private val readWriteLock: ReadWriteLock = ReentrantReadWriteLock(), -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { constructor( initValue: V, readWriteLock: ReadWriteLock = ReentrantReadWriteLock(), @@ -19,7 +19,7 @@ class ReadWriteLockMutableDelegatedField( val rl = readWriteLock.readLock() rl.lock() try { - return mutableDelegatedField.getValue(thisRef, property) + return delegatedField.getValue(thisRef, property) } finally { rl.unlock() } @@ -27,17 +27,17 @@ class ReadWriteLockMutableDelegatedField( override fun setValue(thisRef: T, property: KProperty<*>, value: V) { if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write { - mutableDelegatedField.setValue(thisRef, property, value) + delegatedField.setValue(thisRef, property, value) } else readWriteLock.writeLock().withLock { - mutableDelegatedField.setValue(thisRef, property, value) + delegatedField.setValue(thisRef, property, value) } } override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write { - mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue) + delegatedField.valueOnSet(thisRef, property, value, oldValue) } else readWriteLock.writeLock().withLock { - mutableDelegatedField.setValue(thisRef, property, value) + delegatedField.setValue(thisRef, property, value) } } } \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReflectionDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReflectionDelegatedField.kt new file mode 100644 index 0000000..bd0b876 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ReflectionDelegatedField.kt @@ -0,0 +1,49 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.getFieldForAll +import cn.tursom.core.uncheckedCast +import java.lang.reflect.Field + +class ReflectionDelegatedField( + private val receiver: T, + private val field: Field, +) : MutableDelegatedField { + init { + field.isAccessible = true + } + + override fun getValue(): V = field.get(receiver).uncheckedCast() + + override fun setValue(value: V) { + field.set(receiver, value) + } + + companion object { + fun T.superField( + fieldName: String, + ): MutableDelegatedField { + return ReflectionDelegatedField(this, this.javaClass.getFieldForAll(fieldName)!!) + } + + fun T.field( + field: Field, + ): MutableDelegatedField { + return ReflectionDelegatedField(this, field) + } + + fun T.field( + field: Field, + type: V, + ): MutableDelegatedField { + return ReflectionDelegatedField(this, field) + } + + inline fun T.field( + field: Field, + type: () -> V, + ): MutableDelegatedField { + return ReflectionDelegatedField(this, field) + } + } +} + diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterDelegatedField.kt similarity index 90% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterDelegatedField.kt index 140654c..3d977d3 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterDelegatedField.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterDelegatedField.kt @@ -1,4 +1,4 @@ -package cn.tursom.delegation +package cn.tursom.core.delegation class SetterDelegatedField( override val delegatedField: DelegatedField, diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterMutableDelegatedField.kt new file mode 100644 index 0000000..a1814d1 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SetterMutableDelegatedField.kt @@ -0,0 +1,12 @@ +package cn.tursom.core.delegation + +import kotlin.reflect.KProperty + +class SetterMutableDelegatedField( + override val delegatedField: MutableDelegatedField, + val setter: MutableDelegatedField.(thisRef: T, property: KProperty<*>, value: V) -> Unit, +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + delegatedField.setter(thisRef, property, value) + } +} diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SimpThreadLocalMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SimpThreadLocalMutableDelegatedField.kt new file mode 100644 index 0000000..92c7c7a --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/SimpThreadLocalMutableDelegatedField.kt @@ -0,0 +1,29 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.SimpThreadLocal +import cn.tursom.core.uncheckedCast +import kotlin.reflect.KProperty0 + +class SimpThreadLocalMutableDelegatedField( + private val threadLocal: SimpThreadLocal, +) : MutableDelegatedField { + constructor(new: () -> V) : this(SimpThreadLocal(new = new)) + + + override fun get(key: DelegatedFieldAttachmentKey): K? { + return if (key == Companion || key == ThreadLocalMutableDelegatedField) { + threadLocal.uncheckedCast() + } else { + super.get(key) + } + } + + override fun setValue(value: V) = threadLocal.set(value) + override fun getValue(): V = threadLocal.get() + + companion object : DelegatedFieldAttachmentKey> { + fun getKey() = this.uncheckedCast>>() + fun getKey(property: KProperty0) = + this.uncheckedCast>>() + } +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ThreadLocalMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ThreadLocalMutableDelegatedField.kt new file mode 100644 index 0000000..a036972 --- /dev/null +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/ThreadLocalMutableDelegatedField.kt @@ -0,0 +1,25 @@ +package cn.tursom.core.delegation + +import cn.tursom.core.uncheckedCast +import kotlin.reflect.KProperty0 + +class ThreadLocalMutableDelegatedField( + private val threadLocal: ThreadLocal = ThreadLocal(), +) : MutableDelegatedField { + + override fun get(key: DelegatedFieldAttachmentKey): K? { + return if (key == Companion) { + threadLocal.uncheckedCast() + } else { + super.get(key) + } + } + + override fun setValue(value: V?) = threadLocal.set(value) + override fun getValue(): V? = threadLocal.get() + + companion object : DelegatedFieldAttachmentKey> { + fun getKey() = this.uncheckedCast>>() + fun getKey(property: KProperty0) = this.uncheckedCast>>() + } +} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/delegations.kt similarity index 51% rename from ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt rename to ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/delegations.kt index f0e5428..9438171 100644 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/delegations.kt +++ b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/core/delegation/delegations.kt @@ -1,11 +1,11 @@ @file:Suppress("unused") -package cn.tursom.delegation +package cn.tursom.core.delegation import cn.tursom.core.SimpThreadLocal -import cn.tursom.core.cast import cn.tursom.core.castOrNull import cn.tursom.core.receiver +import cn.tursom.core.uncheckedCast import java.util.concurrent.Executor import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReadWriteLock @@ -19,26 +19,37 @@ import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.isAccessible fun getDelegate(obj: Any?, field: String): DelegatedField<*, *>? { - obj ?: return null - val kProperty1 = obj.javaClass.kotlin.memberProperties.firstOrNull { it.name == field } - kProperty1?.isAccessible = true - val delegate = kProperty1?.getDelegate(obj) - return delegate.castOrNull() + obj ?: return null + val kProperty1 = obj.javaClass.kotlin.memberProperties.firstOrNull { it.name == field } + kProperty1?.isAccessible = true + val delegate = kProperty1?.getDelegate(obj) + return delegate.castOrNull() } val KProperty0.getOwnerDelegated: DelegatedField<*, V>? - get() = getDelegate(receiver, name).castOrNull() + get() = getDelegate(receiver, name).castOrNull() +/** + * 获取委托过后的值 + * 不会触发getter方法 + */ val KProperty0.getDelegatedValue: V? - get() { - val delegate = getDelegate() ?: getOwnerDelegated - return delegate?.castOrNull>()?.getValue() - } + get() { + val delegate = getDelegate() ?: getOwnerDelegated + return delegate?.castOrNull>()?.getValue() + } + +fun KProperty0<*>.getDelegatedAttachmentValue(key: DelegatedFieldAttachmentKey): V? { + val delegated = getOwnerDelegated ?: return null + return delegated[key] +} + +operator fun KProperty0<*>.get(key: DelegatedFieldAttachmentKey): V? = getDelegatedAttachmentValue(key) fun KProperty0.setDelegatedValue(value: V): Boolean { - val delegate = getDelegate() ?: getOwnerDelegated - delegate.castOrNull>()?.setValue(value) ?: return false - return true + val delegate = getDelegate() ?: getOwnerDelegated + delegate.castOrNull>()?.setValue(value) ?: return false + return true } /** @@ -46,50 +57,74 @@ fun KProperty0.setDelegatedValue(value: V): Boolean { */ fun T.delegated(value: V): MutableDelegatedField = MutableDelegatedFieldValue(value) fun T.delegated(@Suppress("UNUSED_PARAMETER") target: T, value: V): MutableDelegatedField = - MutableDelegatedFieldValue(value) + MutableDelegatedFieldValue(value) val KProperty0.delegated: DelegatedField get() = KPropertyDelegatedField(this) val KMutableProperty0.delegated: MutableDelegatedField get() = KPropertyMutableDelegatedField(this) val KProperty0.delegatedNotNull get() = delegated.notNull val KMutableProperty0.delegatedNotNull: MutableDelegatedField get() = delegated.notNull +fun KProperty0.delegatedNotNull(ifNull: () -> Nothing) = delegated.notNull(ifNull) +fun KMutableProperty0.delegatedNotNull(ifNull: () -> Nothing): MutableDelegatedField = + delegated.notNull(ifNull) val DelegatedField.notNull: DelegatedField get() = NotNullDelegatedField(this) val MutableDelegatedField.notNull: MutableDelegatedField - get() = NotNullMutableDelegatedField(cast()) + get() = NotNullMutableDelegatedField(uncheckedCast()) + +fun DelegatedField.notNull(ifNull: () -> Nothing): DelegatedField = + NotNullDelegatedField(this, ifNull) + +fun MutableDelegatedField.notNull(ifNull: () -> Nothing): MutableDelegatedField = + NotNullMutableDelegatedField(uncheckedCast(), ifNull) val MutableDelegatedField.locked: MutableDelegatedField get() = LockMutableDelegatedField(this) fun MutableDelegatedField.locked(lock: Lock = ReentrantLock()): MutableDelegatedField = - LockMutableDelegatedField(this, lock) + LockMutableDelegatedField(this, lock) val MutableDelegatedField.readWriteLocked: MutableDelegatedField - get() = ReadWriteLockMutableDelegatedField(this) + get() = ReadWriteLockMutableDelegatedField(this) fun MutableDelegatedField.readWriteLocked(readWriteLock: ReadWriteLock = ReentrantReadWriteLock()): MutableDelegatedField = - ReadWriteLockMutableDelegatedField(this, readWriteLock) + ReadWriteLockMutableDelegatedField(this, readWriteLock) + + +fun ThreadLocal.delegated(): MutableDelegatedField = ThreadLocalMutableDelegatedField(this) +fun T.delegated( + threadLocal: ThreadLocal, +): MutableDelegatedField = ThreadLocalMutableDelegatedField(threadLocal) fun T.threadLocalDelegated(): MutableDelegatedField = ThreadLocalMutableDelegatedField() -fun T.threadLocalDelegated(type: Class): MutableDelegatedField = ThreadLocalMutableDelegatedField() -fun T.threadLocalDelegated(type: KClass): MutableDelegatedField = - ThreadLocalMutableDelegatedField() +fun T.threadLocalDelegated(type: V?): MutableDelegatedField = ThreadLocalMutableDelegatedField() +fun T.threadLocalDelegated(type: Class): MutableDelegatedField = + ThreadLocalMutableDelegatedField() -fun T.threadLocalDelegated(new: () -> V): MutableDelegatedField = SimpThreadLocalMutableDelegatedField(new) -fun T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal, new: () -> V): MutableDelegatedField = - SimpThreadLocalMutableDelegatedField(simpThreadLocal, new) +fun T.threadLocalDelegated(type: KClass): MutableDelegatedField = + ThreadLocalMutableDelegatedField() + +fun SimpThreadLocal.delegated(): MutableDelegatedField = + SimpThreadLocalMutableDelegatedField(this) + +fun T.threadLocalDelegated( + threadLocal: ThreadLocal = ThreadLocal(), + new: () -> V, +): MutableDelegatedField = SimpThreadLocalMutableDelegatedField(SimpThreadLocal(threadLocal, new)) +//fun T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal): MutableDelegatedField = +// SimpThreadLocalMutableDelegatedField(simpThreadLocal) fun MutableDelegatedField.filter(filter: T.(old: V, new: V) -> Boolean): MutableDelegatedField = - FilterDelegatedField(this, filter) + FilterDelegatedField(this, filter) fun DelegatedField.setter(setter: DelegatedField.(value: V) -> Unit): DelegatedField = - SetterDelegatedField(this, setter) + SetterDelegatedField(this, setter) fun MutableDelegatedField.setter(setter: MutableDelegatedField.(thisRef: T, property: KProperty<*>, value: V) -> Unit): MutableDelegatedField = - SetterMutableDelegatedField(this, setter) + SetterMutableDelegatedField(this, setter) fun DelegatedField.getter(getter: DelegatedField.(thisRef: T, property: KProperty<*>) -> V): DelegatedField = - GetterDelegatedField(this, getter) + GetterDelegatedField(this, getter) fun MutableDelegatedField.getter(getter: MutableDelegatedField.(thisRef: T, property: KProperty<*>) -> V): MutableDelegatedField = - GetterMutableDelegatedField(this, getter) + GetterMutableDelegatedField(this, getter) fun MutableDelegatedField.withExecutor(executor: Executor): MutableDelegatedField = - ExecutorMutableDelegatedField(this, executor) + ExecutorMutableDelegatedField(this, executor) diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt deleted file mode 100644 index 0bb2f9f..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DecoratorMutableDelegatedField.kt +++ /dev/null @@ -1,6 +0,0 @@ -package cn.tursom.delegation - -interface DecoratorMutableDelegatedField : DecoratorDelegatedField { - val mutableDelegatedField: MutableDelegatedField - override val delegatedField: DelegatedField get() = mutableDelegatedField -} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt deleted file mode 100644 index 1f26256..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/DelegatedFieldAttachmentKey.kt +++ /dev/null @@ -1,3 +0,0 @@ -package cn.tursom.delegation - -interface DelegatedFieldAttachmentKey \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt deleted file mode 100644 index b8a9f0a..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/GetterMutableDelegatedField.kt +++ /dev/null @@ -1,10 +0,0 @@ -package cn.tursom.delegation - -import kotlin.reflect.KProperty - -class GetterMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, - private val getter: MutableDelegatedField.(thisRef: T, property: KProperty<*>) -> V, -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { - override fun getValue(thisRef: T, property: KProperty<*>): V = mutableDelegatedField.getter(thisRef, property) -} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt deleted file mode 100644 index 7e82e96..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullDelegatedField.kt +++ /dev/null @@ -1,7 +0,0 @@ -package cn.tursom.delegation - -import cn.tursom.core.cast - -class NotNullDelegatedField( - override val delegatedField: DelegatedField, -) : DelegatedField by delegatedField.cast(), DecoratorDelegatedField \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt deleted file mode 100644 index 9e2b9ad..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/NotNullMutableDelegatedField.kt +++ /dev/null @@ -1,8 +0,0 @@ -package cn.tursom.delegation - -import cn.tursom.core.cast - -class NotNullMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, -) : MutableDelegatedField by mutableDelegatedField.cast(), DecoratorMutableDelegatedField - diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt deleted file mode 100644 index 5bfb42b..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SetterMutableDelegatedField.kt +++ /dev/null @@ -1,12 +0,0 @@ -package cn.tursom.delegation - -import kotlin.reflect.KProperty - -class SetterMutableDelegatedField( - override val mutableDelegatedField: MutableDelegatedField, - val setter: MutableDelegatedField.(thisRef: T, property: KProperty<*>, value: V) -> Unit, -) : MutableDelegatedField by mutableDelegatedField, DecoratorMutableDelegatedField { - override fun setValue(thisRef: T, property: KProperty<*>, value: V) { - mutableDelegatedField.setter(thisRef, property, value) - } -} diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt deleted file mode 100644 index 0aadf5d..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/SimpThreadLocalMutableDelegatedField.kt +++ /dev/null @@ -1,14 +0,0 @@ -package cn.tursom.delegation - -import cn.tursom.core.SimpThreadLocal - - -class SimpThreadLocalMutableDelegatedField( - private val threadLocal: SimpThreadLocal, - val new: () -> V -) : MutableDelegatedField { - constructor(new: () -> V) : this(SimpThreadLocal(new = new), new) - - override fun setValue(value: V) = threadLocal.set(value) - override fun getValue(): V = threadLocal.get() -} \ No newline at end of file diff --git a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt b/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt deleted file mode 100644 index ba5ee3f..0000000 --- a/ts-core/ts-delegation/src/main/kotlin/cn/tursom/delegation/ThreadLocalMutableDelegatedField.kt +++ /dev/null @@ -1,8 +0,0 @@ -package cn.tursom.delegation - -class ThreadLocalMutableDelegatedField( - private val threadLocal: ThreadLocal = ThreadLocal() -) : MutableDelegatedField { - override fun setValue(value: V?) = threadLocal.set(value) - override fun getValue(): V? = threadLocal.get() -} \ No newline at end of file diff --git a/ts-core/ts-delegation/ts-observer/build.gradle.kts b/ts-core/ts-delegation/ts-observer/build.gradle.kts new file mode 100644 index 0000000..b3a0202 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/build.gradle.kts @@ -0,0 +1,32 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + implementation(project(":ts-core")) + implementation(project(":ts-core:ts-delegation")) +} + +@kotlin.Suppress("UNCHECKED_CAST") +(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks) + +tasks.register("install") { + finalizedBy(tasks["publishToMavenLocal"]) +} + +publishing { + publications { + create("maven") { + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + + from(components["java"]) + try { + artifact(tasks["kotlinSourcesJar"]) + } catch (e: Exception) { + } + } + } +} diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listenable.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listenable.kt new file mode 100644 index 0000000..0b0934b --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listenable.kt @@ -0,0 +1,10 @@ +package cn.tursom.core.delegation.observer + +/** + * 标识一个属性可以被指定的 FieldChangeListener 监听 + * 属性的实现者应该实现相应的逻辑 + */ +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class Listenable \ No newline at end of file diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableListener.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableListener.kt new file mode 100644 index 0000000..741af94 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableListener.kt @@ -0,0 +1,6 @@ +package cn.tursom.core.delegation.observer + +interface ListenableListener : Listener { + infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener +} diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableMutableDelegatedField.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableMutableDelegatedField.kt new file mode 100644 index 0000000..f3f25b8 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/ListenableMutableDelegatedField.kt @@ -0,0 +1,64 @@ +package cn.tursom.core.delegation.observer + +import cn.tursom.core.delegation.DecoratorMutableDelegatedField +import cn.tursom.core.delegation.DelegatedFieldAttachmentKey +import cn.tursom.core.delegation.MutableDelegatedField +import cn.tursom.core.uncheckedCast +import java.util.concurrent.ConcurrentLinkedDeque +import kotlin.reflect.KProperty + +@Listenable +class ListenableMutableDelegatedField( + override val delegatedField: MutableDelegatedField, +) : MutableDelegatedField by delegatedField, DecoratorMutableDelegatedField { + companion object : DelegatedFieldAttachmentKey + + override fun get(key: DelegatedFieldAttachmentKey): K? { + return if (key == Companion) true.uncheckedCast() else super.get(key) + } + + private val listenerList = ConcurrentLinkedDeque Unit>() + + override fun setValue(thisRef: T, property: KProperty<*>, value: V) { + val oldValue = getValue() + listenerList.forEach { + thisRef.it(oldValue, value) + } + delegatedField.setValue(thisRef, property, value) + } + + override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) { + listenerList.forEach { + thisRef.it(oldValue, value) + } + delegatedField.valueOnSet(thisRef, property, value, oldValue) + } + + fun addListener(listener: T.(old: V, new: V) -> Unit): Listener { + var catch: (T.(old: V, new: V, e: Throwable) -> Unit)? = null + var finally: (T.(old: V, new: V) -> Unit)? = null + listenerList.add { old, new -> + try { + listener(old, new) + } catch (e: Throwable) { + catch?.invoke(this, old, new, e) + } finally { + finally?.invoke(this, old, new) + } + } + return object : Listener { + override fun cancel() = listenerList.remove(listener) + + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener { + catch = handler + return this + } + + override fun finally(handler: T.(old: V, new: V) -> Unit): Listener { + finally = handler + return this + } + + } + } +} \ No newline at end of file diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listener.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listener.kt new file mode 100644 index 0000000..ccad2fb --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/Listener.kt @@ -0,0 +1,7 @@ +package cn.tursom.core.delegation.observer + +interface Listener { + fun cancel(): Boolean + infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener + infix fun finally(handler: T.(old: V, new: V) -> Unit): Listener +} \ No newline at end of file diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/UnmonitoredFieldException.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/UnmonitoredFieldException.kt new file mode 100644 index 0000000..dd4bb63 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/UnmonitoredFieldException.kt @@ -0,0 +1,9 @@ +package cn.tursom.core.delegation.observer + +class UnmonitoredFieldException : Exception { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) + constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(message, cause, enableSuppression, writableStackTrace) +} \ No newline at end of file diff --git a/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/delegations.kt b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/delegations.kt new file mode 100644 index 0000000..792a967 --- /dev/null +++ b/ts-core/ts-delegation/ts-observer/src/main/kotlin/cn/tursom/core/delegation/observer/delegations.kt @@ -0,0 +1,109 @@ +@file:Suppress("unused") + +package cn.tursom.core.delegation.observer + +import cn.tursom.core.UncheckedCast +import cn.tursom.core.cast +import cn.tursom.core.delegation.* +import cn.tursom.core.receiver +import java.util.concurrent.ConcurrentLinkedQueue +import kotlin.reflect.KMutableProperty0 +import kotlin.reflect.KProperty0 +import kotlin.reflect.jvm.isAccessible + + +@Listenable +fun KMutableProperty0.listenable(): MutableDelegatedField { + isAccessible = true + val delegate = getDelegate() + return if (delegate is MutableDelegatedField<*, *> && delegate[ListenableMutableDelegatedField] == true) { + @OptIn(UncheckedCast::class) + delegate.cast() + } else { + @OptIn(UncheckedCast::class) + (ListenableMutableDelegatedField(KPropertyMutableDelegatedField(cast()))) + } +} + +@Listenable +fun listenable(initValue: V): MutableDelegatedField = ListenableMutableDelegatedField( + MutableDelegatedFieldValue(initValue) +) + +@Listenable +fun MutableDelegatedField.listenable(): MutableDelegatedField = + ListenableMutableDelegatedField(this) + +@JvmName("listenable1") +@Listenable +fun listenable(delegatedField: MutableDelegatedField): MutableDelegatedField = + ListenableMutableDelegatedField(delegatedField) + + +infix operator fun ListenableListener.plus(listener: T.(old: V, new: V) -> Unit): Listener = + addListener(listener) + +@OptIn(Listenable::class) +fun KProperty0.getListenableMutableDelegatedField(): ListenableMutableDelegatedField? { + isAccessible = true + var delegate = getDelegate() ?: getDelegate(receiver, name) + if (delegate is DelegatedField<*, *>) { + while (true) { + if (delegate is ListenableMutableDelegatedField<*, *>) { + @OptIn(UncheckedCast::class) + return delegate.cast() + } + if (delegate is DecoratorDelegatedField<*, *>) { + delegate = delegate.delegatedField + } else { + break + } + } + } else if (delegate is KProperty0<*> && delegate != this) { + @OptIn(UncheckedCast::class) + return delegate.cast>().getListenableMutableDelegatedField() + } + return null +} + +inline fun T.addChangeListener( + property: T.() -> KProperty0, +): ListenableListener { + val kProperty0 = property() + + @OptIn(Listenable::class, UncheckedCast::class) + val delegatedField = kProperty0 + .getListenableMutableDelegatedField() + .cast?>() + ?: throw UnmonitoredFieldException(kProperty0.toString()) + return object : ListenableListener { + private val selfList = ConcurrentLinkedQueue>() + override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener { + @OptIn(Listenable::class) + val listener1 = delegatedField.addListener(listener) + selfList.add(listener1) + return listener1 + } + + override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener { + selfList.forEach { + it.catch(handler) + } + return this + } + + override fun cancel(): Boolean { + selfList.forEach { + it.cancel() + } + return true + } + + override fun finally(handler: T.(old: V, new: V) -> Unit): Listener { + selfList.forEach { + it.finally(handler) + } + return this + } + } +} \ No newline at end of file diff --git a/ts-core/ts-encrypt/build.gradle.kts b/ts-core/ts-encrypt/build.gradle.kts index 1f9de67..7f6ef95 100644 --- a/ts-core/ts-encrypt/build.gradle.kts +++ b/ts-core/ts-encrypt/build.gradle.kts @@ -26,7 +26,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-encrypt/src/main/kotlin/cn/tursom/core/encrypt/ECC.kt b/ts-core/ts-encrypt/src/main/kotlin/cn/tursom/core/encrypt/ECC.kt index f881ddf..1ca6f46 100644 --- a/ts-core/ts-encrypt/src/main/kotlin/cn/tursom/core/encrypt/ECC.kt +++ b/ts-core/ts-encrypt/src/main/kotlin/cn/tursom/core/encrypt/ECC.kt @@ -1,8 +1,7 @@ package cn.tursom.core.encrypt import cn.tursom.core.Unsafe -import cn.tursom.core.cast -import sun.security.ec.CurveDB +import cn.tursom.core.uncheckedCast import java.security.KeyFactory import java.security.KeyPair import java.security.KeyPairGenerator @@ -17,7 +16,7 @@ import java.security.spec.X509EncodedKeySpec @Suppress("unused", "MemberVisibilityCanBePrivate") class ECC( publicKey: ECPublicKey, - privateKey: ECPrivateKey? = null + privateKey: ECPrivateKey? = null, ) : AbstractPublicKeyEncrypt("EC", publicKey, privateKey) { override val decryptMaxLen = Int.MAX_VALUE @@ -41,7 +40,7 @@ class ECC( constructor( keySize: Int = 256, - standardCurveLine: String = StandardCurveLine.secp256k1.name.replace('_', ' ') + standardCurveLine: String = StandardCurveLine.secp256k1.name.replace('_', ' '), ) : this( keySize, ECGenParameterSpec(standardCurveLine) @@ -71,8 +70,12 @@ class ECC( companion object { val standardCurveLineSet by lazy { - Unsafe { - CurveDB::class.java["nameMap"].cast>().keys + try { + Unsafe { + Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast>().keys + } + } catch (e: Exception) { + emptySet() } } } diff --git a/ts-core/ts-hash/build.gradle.kts b/ts-core/ts-hash/build.gradle.kts index e45ce1c..9d991f1 100644 --- a/ts-core/ts-hash/build.gradle.kts +++ b/ts-core/ts-hash/build.gradle.kts @@ -24,7 +24,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-json/build.gradle.kts b/ts-core/ts-json/build.gradle.kts index 685c49b..9877fba 100644 --- a/ts-core/ts-json/build.gradle.kts +++ b/ts-core/ts-json/build.gradle.kts @@ -26,7 +26,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-log/build.gradle.kts b/ts-core/ts-log/build.gradle.kts index cd403e4..e73a343 100644 --- a/ts-core/ts-log/build.gradle.kts +++ b/ts-core/ts-log/build.gradle.kts @@ -4,10 +4,10 @@ plugins { } dependencies { - implementation(project(":")) - implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.29") - implementation(group = "ch.qos.logback", name = "logback-core", version = "1.2.3") - implementation(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3") + implementation(project(":ts-core")) + api(group = "org.slf4j", name = "slf4j-api", version = "1.7.29") + api(group = "ch.qos.logback", name = "logback-core", version = "1.2.3") + api(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3") } @kotlin.Suppress("UNCHECKED_CAST") @@ -26,7 +26,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-log/src/main/kotlin/cn/tursom/log/Slf4j.kt b/ts-core/ts-log/src/main/kotlin/cn/tursom/log/Slf4j.kt index e6bc0b6..1cec382 100644 --- a/ts-core/ts-log/src/main/kotlin/cn/tursom/log/Slf4j.kt +++ b/ts-core/ts-log/src/main/kotlin/cn/tursom/log/Slf4j.kt @@ -2,7 +2,7 @@ package cn.tursom.log import org.slf4j.Logger -interface Slf4j : TrySlf4j { +interface Slf4j : TrySlf4j, Logger { override val log: Logger override val logger get() = log override val sfl4j get() = log diff --git a/ts-core/ts-log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt b/ts-core/ts-log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt index f35ce1a..4bf8d70 100644 --- a/ts-core/ts-log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt +++ b/ts-core/ts-log/src/main/kotlin/cn/tursom/log/impl/Slf4jImpl.kt @@ -1,13 +1,14 @@ package cn.tursom.log.impl +import cn.tursom.core.getCallerClassName import cn.tursom.log.Slf4j import org.slf4j.Logger import org.slf4j.LoggerFactory -import sun.reflect.Reflection import kotlin.reflect.KClass import kotlin.reflect.jvm.jvmName -open class Slf4jImpl( +open class Slf4jImpl constructor( + @field:Transient override val log: Logger, ) : Slf4j, Logger by log { constructor(name: String? = null) : this(LoggerFactory.getLogger(name ?: loggerName)) @@ -27,20 +28,8 @@ open class Slf4jImpl( companion object { private val thisClassName = listOf(this::class.java.name.dropLast(10), this::class.java.name) private val loggerName: String - get() = getCallerClassName() ?: throw UnsupportedOperationException() - - private fun getCallerClassName(): String? { - var clazz: Class<*>? - var callStackDepth = 1 - do { - @Suppress("DEPRECATION") - clazz = Reflection.getCallerClass(callStackDepth++) - if (clazz?.name !in thisClassName) { - break - } - } while (clazz != null) - return clazz?.name - } + get() = getCallerClassName(thisClassName)?.substringBefore('$') + ?: throw UnsupportedOperationException() inline fun getLogger(name: String): Logger = LoggerFactory.getLogger(name) diff --git a/ts-core/ts-mail/build.gradle.kts b/ts-core/ts-mail/build.gradle.kts index 1d536b7..b902885 100644 --- a/ts-core/ts-mail/build.gradle.kts +++ b/ts-core/ts-mail/build.gradle.kts @@ -24,7 +24,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-pool/build.gradle.kts b/ts-core/ts-pool/build.gradle.kts index 4fc041d..9d5081f 100644 --- a/ts-core/ts-pool/build.gradle.kts +++ b/ts-core/ts-pool/build.gradle.kts @@ -25,7 +25,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-ws-client/build.gradle.kts b/ts-core/ts-ws-client/build.gradle.kts index 139705c..ed155e0 100644 --- a/ts-core/ts-ws-client/build.gradle.kts +++ b/ts-core/ts-ws-client/build.gradle.kts @@ -17,6 +17,10 @@ tasks.register("install") { finalizedBy(tasks["publishToMavenLocal"]) } +artifacts { + archives(tasks["kotlinSourcesJar"]) +} + publishing { publications { create("maven") { @@ -26,7 +30,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/AutoCloseWebSocketHandler.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/AutoCloseWebSocketHandler.kt new file mode 100644 index 0000000..2bfd407 --- /dev/null +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/AutoCloseWebSocketHandler.kt @@ -0,0 +1,26 @@ +package cn.tursom.core.ws + +import cn.tursom.core.buffer.ByteBuffer +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame + +interface AutoCloseWebSocketHandler : WebSocketHandler { + override fun readMessage(client: WebSocketClient, msg: TextWebSocketFrame) { + super.readMessage(client, msg) + msg.release() + } + + override fun readMessage(client: WebSocketClient, msg: ByteBuffer) { + super.readMessage(client, msg) + msg.close() + } + + override fun readPing(client: WebSocketClient, msg: ByteBuffer) { + super.readPing(client, msg) + msg.close() + } + + override fun readPong(client: WebSocketClient, msg: ByteBuffer) { + super.readPong(client, msg) + msg.close() + } +} \ No newline at end of file diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt index c196145..f735842 100644 --- a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt @@ -5,10 +5,7 @@ import cn.tursom.core.buffer.impl.NettyByteBuffer import io.netty.bootstrap.Bootstrap import io.netty.buffer.ByteBuf import io.netty.buffer.Unpooled -import io.netty.channel.Channel -import io.netty.channel.ChannelFuture -import io.netty.channel.ChannelInitializer -import io.netty.channel.EventLoopGroup +import io.netty.channel.* import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.SocketChannel import io.netty.channel.socket.nio.NioSocketChannel @@ -33,9 +30,12 @@ class WebSocketClient( val maxContextLength: Int = 4096, private val headers: Map? = null, private val handshakerUri: URI? = null, + val autoRelease: Boolean = true, + var initChannel: ((ch: SocketChannel) -> Unit)? = null ) { private val uri: URI = URI.create(url) - internal var ch: Channel? = null + var ch: Channel? = null + internal set fun open() { close() @@ -68,10 +68,12 @@ class WebSocketClient( headers?.forEach { (k, v) -> httpHeaders[k] = v } - val handshakerAdapter = WebSocketClientHandshakerAdapter(WebSocketClientHandshakerFactory.newHandshaker( - handshakerUri ?: uri, WebSocketVersion.V13, null, true, httpHeaders - ), this, handler) - val handler = WebSocketClientChannelHandler(this, handler) + val handshakerAdapter = WebSocketClientHandshakerAdapter( + WebSocketClientHandshakerFactory.newHandshaker( + handshakerUri ?: uri, WebSocketVersion.V13, null, true, httpHeaders + ), this, handler + ) + val handler = WebSocketClientChannelHandler(this, handler, autoRelease) val bootstrap = Bootstrap() bootstrap.group(group) .channel(NioSocketChannel::class.java) @@ -90,27 +92,25 @@ class WebSocketClient( addLast(WebSocketClientCompressionHandler.INSTANCE) } addLast(handshakerAdapter) - //if (log) { - // addLast(LoggingHandler()) - //} addLast(handler) if (autoWrap) { addLast(WebSocketFrameWrapper) } } + initChannel?.invoke(ch) } }) bootstrap.connect(uri.host, port) //handler.handshakeFuture().sync() } - fun close(reasonText: String? = null) { + fun close(reasonText: String? = null): ChannelFuture? { if (reasonText == null) { ch?.writeAndFlush(CloseWebSocketFrame()) } else { ch?.writeAndFlush(CloseWebSocketFrame(WebSocketCloseStatus.NORMAL_CLOSURE, reasonText)) - } - ch?.closeFuture()?.sync() + }?.addListener(ChannelFutureListener.CLOSE) + return ch?.closeFuture() } fun write(text: String): ChannelFuture { @@ -190,6 +190,6 @@ class WebSocketClient( } companion object { - private val group: EventLoopGroup = NioEventLoopGroup() + val group: EventLoopGroup = NioEventLoopGroup() } } \ No newline at end of file diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientChannelHandler.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientChannelHandler.kt index 1bea2e3..75bee11 100644 --- a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientChannelHandler.kt +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientChannelHandler.kt @@ -8,7 +8,8 @@ import io.netty.handler.codec.http.websocketx.* class WebSocketClientChannelHandler( val client: WebSocketClient, val handler: WebSocketHandler, -) : SimpleChannelInboundHandler() { + private val autoRelease: Boolean = true, +) : SimpleChannelInboundHandler(autoRelease) { override fun channelInactive(ctx: ChannelHandlerContext) { handler.onClose(client) @@ -24,7 +25,11 @@ class WebSocketClientChannelHandler( is BinaryWebSocketFrame -> handler.readMessage(client, msg) is PingWebSocketFrame -> handler.readPing(client, msg) is PongWebSocketFrame -> handler.readPong(client, msg) - is CloseWebSocketFrame -> ch.close() + is CloseWebSocketFrame -> { + if (!autoRelease) while (msg.refCnt() != 0) msg.release() + ch.close() + } + else -> if (!autoRelease) while (msg.refCnt() != 0) msg.release() } } } \ No newline at end of file diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientHandshakerAdapter.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientHandshakerAdapter.kt index c7d28f9..b41eafb 100644 --- a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientHandshakerAdapter.kt +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClientHandshakerAdapter.kt @@ -27,8 +27,8 @@ class WebSocketClientHandshakerAdapter( if (!handshaker.isHandshakeComplete) { handshaker.finishHandshake(ctx.channel(), msg) handshakeFuture!!.setSuccess() - msg.retain() - ctx.fireChannelRead(msg) + //msg.retain() + //ctx.fireChannelRead(msg) handler.onOpen(client) return } else { diff --git a/ts-core/ts-xml/build.gradle.kts b/ts-core/ts-xml/build.gradle.kts new file mode 100644 index 0000000..10cc33e --- /dev/null +++ b/ts-core/ts-xml/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + api(project(":")) + // 解析XML https://mvnrepository.com/artifact/org.dom4j/dom4j + api(group = "org.dom4j", name = "dom4j", version = "2.1.3") +} + +@kotlin.Suppress("UNCHECKED_CAST") +(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks) + +tasks.register("install") { + finalizedBy(tasks["publishToMavenLocal"]) +} + +publishing { + publications { + create("maven") { + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + + from(components["java"]) + try { + artifact(tasks["kotlinSourcesJar"]) + } catch (e: Exception) { + } + } + } +} diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/Xml.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/Xml.kt similarity index 99% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/Xml.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/Xml.kt index b4f5984..427d338 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/Xml.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/Xml.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml +package cn.tursom.core.xml import org.dom4j.Document import org.dom4j.Element diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/XmlDocument.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/XmlDocument.kt similarity index 96% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/XmlDocument.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/XmlDocument.kt index deac7e2..15d7b58 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/XmlDocument.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/XmlDocument.kt @@ -1,6 +1,6 @@ -package cn.tursom.utils.xml +package cn.tursom.core.xml -import cn.tursom.utils.xml.interfaces.* +import cn.tursom.core.xml.interfaces.* object XmlDocument { fun tag(name: String? = null, action: (TextPotableXmlElement.() -> Unit)? = null): TextXmlElement { diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/annotations.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/annotations.kt similarity index 98% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/annotations.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/annotations.kt index 0ddb13d..5157441 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/annotations.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/annotations.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml +package cn.tursom.core.xml enum class ElementTarget { Attribute, ElementText, SubElement diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerPotableXmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerPotableXmlElement.kt similarity index 92% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerPotableXmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerPotableXmlElement.kt index ba642d1..b5a9397 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerPotableXmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerPotableXmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface ElementContainerPotableXmlElement : ElementContainerXmlElement, PotableXmlElement { val size: Int diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerXmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerXmlElement.kt similarity index 69% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerXmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerXmlElement.kt index f9b416c..4e82778 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/ElementContainerXmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/ElementContainerXmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface ElementContainerXmlElement : XmlElement { val subElement: List diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/PotableXmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/PotableXmlElement.kt similarity index 87% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/PotableXmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/PotableXmlElement.kt index f044a46..7bf1640 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/PotableXmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/PotableXmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface PotableXmlElement : XmlElement { override var name: String diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextPotableXmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextPotableXmlElement.kt similarity index 71% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextPotableXmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextPotableXmlElement.kt index aa7d802..9594b09 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextPotableXmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextPotableXmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface TextPotableXmlElement : TextXmlElement, PotableXmlElement { override var text: String diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextXmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextXmlElement.kt similarity index 60% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextXmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextXmlElement.kt index 8cb64ca..730f375 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/TextXmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/TextXmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface TextXmlElement : XmlElement { val text: String diff --git a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/XmlElement.kt b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/XmlElement.kt similarity index 96% rename from utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/XmlElement.kt rename to ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/XmlElement.kt index 5723127..a157aee 100644 --- a/utils/xml/src/main/kotlin/cn/tursom/utils/xml/interfaces/XmlElement.kt +++ b/ts-core/ts-xml/src/main/kotlin/cn/tursom/core/xml/interfaces/XmlElement.kt @@ -1,4 +1,4 @@ -package cn.tursom.utils.xml.interfaces +package cn.tursom.core.xml.interfaces interface XmlElement { val name: String diff --git a/ts-core/ts-yaml/build.gradle.kts b/ts-core/ts-yaml/build.gradle.kts index 9dd3646..492d944 100644 --- a/ts-core/ts-yaml/build.gradle.kts +++ b/ts-core/ts-yaml/build.gradle.kts @@ -25,7 +25,7 @@ publishing { from(components["java"]) try { - artifact(tasks["sourcesJar"]) + artifact(tasks["kotlinSourcesJar"]) } catch (e: Exception) { } } diff --git a/ts-database/build.gradle.kts b/ts-database/build.gradle.kts new file mode 100644 index 0000000..2342fa7 --- /dev/null +++ b/ts-database/build.gradle.kts @@ -0,0 +1,37 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + api(project(":")) + implementation(project(":ts-core")) + implementation(project(":ts-core:ts-clone")) + implementation(project(":ts-core:ts-log")) + api(group = "me.liuwj.ktorm", name = "ktorm-core", version = "3.1.0") + compileOnly(group = "com.baomidou", name = "mybatis-plus", version = "3.4.2") + compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.6") +} + +@kotlin.Suppress("UNCHECKED_CAST") +(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks) + +tasks.register("install") { + finalizedBy(tasks["publishToMavenLocal"]) +} + +publishing { + publications { + create("maven") { + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + + from(components["java"]) + try { + artifact(tasks["kotlinSourcesJar"]) + } catch (e: Exception) { + } + } + } +} diff --git a/ts-database/src/main/kotlin/cn/tursom/database/AutoTable.kt b/ts-database/src/main/kotlin/cn/tursom/database/AutoTable.kt new file mode 100644 index 0000000..617ce71 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/AutoTable.kt @@ -0,0 +1,82 @@ +package cn.tursom.database + +import cn.tursom.core.clone.Property +import cn.tursom.core.clone.inject +import cn.tursom.core.clone.instance +import cn.tursom.core.uncheckedCast +import com.baomidou.mybatisplus.annotation.TableField +import me.liuwj.ktorm.dsl.QueryRowSet +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.util.concurrent.ConcurrentHashMap +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty0 +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.javaField + +open class AutoTable( + entityClass: KClass, + tableName: String = entityClass.tableName, + alias: String? = null, + catalog: String? = null, + schema: String? = null, + val unsafe: Boolean = true, +) : BaseTable(tableName, alias, catalog, schema, entityClass) { + private val fieldMap: Map> + private val fieldColumns: MutableMap, Column<*>> = HashMap() + private val fieldNameColumnMap: MutableMap> = HashMap() + + init { + fieldMap = entityClass.memberProperties.associateBy { it.simpTableField } + entityClass.memberProperties.forEach { + val field = it.javaField ?: return@forEach + val tableField: TableField? = field.getAnnotation(TableField::class.java) + if (tableField?.exist == false) return@forEach + //TypeAdapterFactory.register(this, it) + val column = TypeAdapterFactory.register(this, it) ?: return@forEach + fieldColumns[it] = column + fieldNameColumnMap[it.name] = column + } + } + + override fun doCreateEntity(row: QueryRowSet, withReferences: Boolean): T { + val instance = instance(unsafe, entityClass!!.java) + columns.forEach { + val field = fieldMap[it.name] ?: return@forEach + row[it]?.inject(instance, field.uncheckedCast>()) + } + return instance + } + + operator fun get(property: KProperty1): Column = fieldColumns[property].uncheckedCast() + //operator fun get(property: KProperty1): Column = this[property.simpTableField].cast() + + fun field(): FieldProxy = fieldProxyInstance.uncheckedCast() + fun field(property: KProperty0<*>): Column = fieldNameColumnMap[property.name].uncheckedCast() + + companion object { + private val fieldProxyInstance = FieldProxy() + private val autoTableMap = ConcurrentHashMap, AutoTable<*>>() + operator fun get(clazz: KClass): AutoTable = get(clazz.java) + + operator fun get(clazz: Class): AutoTable { + var autoTable = autoTableMap[clazz] + if (autoTable == null) { + synchronized(autoTableMap) { + autoTable = AutoTable(clazz.kotlin) + autoTableMap[clazz] = autoTable.uncheckedCast() + } + } + return autoTable.uncheckedCast() + } + + class FieldProxy { + operator fun getValue( + autoTable: AutoTable, + property: KProperty<*>, + ): Column = autoTable.fieldNameColumnMap[property.name].uncheckedCast() + } + } +} diff --git a/ts-database/src/main/kotlin/cn/tursom/database/JsonType.kt b/ts-database/src/main/kotlin/cn/tursom/database/JsonType.kt new file mode 100644 index 0000000..430b775 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/JsonType.kt @@ -0,0 +1,27 @@ +package cn.tursom.database + +import cn.tursom.core.Utils +import com.google.gson.Gson +import me.liuwj.ktorm.schema.SqlType +import java.lang.reflect.Type +import java.sql.PreparedStatement +import java.sql.ResultSet +import java.sql.Types + +@Suppress("MemberVisibilityCanBePrivate") +class JsonType( + val clazz: Type, + type: Int = Types.VARCHAR, + val gson: Gson = Utils.gson, +) : SqlType(type, "json") { + constructor(clazz: Class, type: Int = Types.VARCHAR) : this(clazz as Type, type) + + override fun doGetResult(rs: ResultSet, index: Int): T? { + val result = rs.getString(index) ?: return null + return gson.fromJson(result, clazz) + } + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: T) { + ps.setString(index, gson.toJson(parameter)) + } +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/SqlExtension.kt b/ts-database/src/main/kotlin/cn/tursom/database/SqlExtension.kt new file mode 100644 index 0000000..5559a70 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/SqlExtension.kt @@ -0,0 +1,150 @@ +@file:Suppress("unused") + +package cn.tursom.database + +import cn.tursom.core.Utils +import cn.tursom.core.uncheckedCast +import com.google.gson.Gson +import me.liuwj.ktorm.dsl.Query +import me.liuwj.ktorm.dsl.QueryRowSet +import me.liuwj.ktorm.schema.* +import java.math.BigDecimal +import java.sql.Date +import java.sql.Time +import java.sql.Timestamp +import java.sql.Types +import java.time.* +import java.util.* +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.javaField +import kotlin.reflect.jvm.javaType + +val KProperty<*>.table + get() = AutoTable[javaField!!.declaringClass].uncheckedCast>() +val KProperty.sql + get() = table[this.uncheckedCast>()] + +inline val KProperty1.table + get() = AutoTable[T::class.java] + +inline val KProperty1.sql + get() = table[this] + +fun Query.getOne(transform: (rowSet: QueryRowSet) -> T): T? = if (rowSet.next()) { + transform(rowSet) +} else { + null +} + +inline fun Query.getOne(): T? = if (rowSet.next()) { + AutoTable[T::class].createEntity(rowSet) +} else { + null +} + +fun BaseTable.json( + field: KProperty1, + type: Int = Types.VARCHAR, + gson: Gson = Utils.gson, +): Column { + val sqlType = JsonType(field.returnType.javaType, type, gson) + return this.registerColumn(field.simpTableField, sqlType) +} + +fun BaseTable.boolean( + field: KProperty1, +) = boolean(field.simpTableField) + +fun BaseTable.int( + field: KProperty1, +) = int(field.simpTableField) + +fun BaseTable.long( + field: KProperty1, +) = long(field.simpTableField) + +fun BaseTable.float( + field: KProperty1, +) = float(field.simpTableField) + +fun BaseTable.double( + field: KProperty1, +) = double(field.simpTableField) + +fun BaseTable.decimal( + field: KProperty1, +) = decimal(field.simpTableField) + +fun BaseTable.varchar( + field: KProperty1, +) = varchar(field.simpTableField) + +fun BaseTable.text( + field: KProperty1, +) = text(field.simpTableField) + +fun BaseTable.blob( + field: KProperty1, +) = blob(field.simpTableField) + +fun BaseTable.bytes( + field: KProperty1, +) = bytes(field.simpTableField) + +fun BaseTable.jdbcTimestamp( + field: KProperty1, +) = jdbcTimestamp(field.simpTableField) + +fun BaseTable.jdbcDate( + field: KProperty1, +) = jdbcDate(field.simpTableField) + +fun BaseTable.jdbcTime( + field: KProperty1, +) = jdbcTime(field.simpTableField) + +fun BaseTable.timestamp( + field: KProperty1, +) = timestamp(field.simpTableField) + +fun BaseTable.datetime( + field: KProperty1, +) = datetime(field.simpTableField) + +fun BaseTable.date( + field: KProperty1, +) = date(field.simpTableField) + +fun BaseTable.time( + field: KProperty1, +) = time(field.simpTableField) + +fun BaseTable.monthDay( + field: KProperty1, +) = monthDay(field.simpTableField) + + +fun BaseTable.yearMonth( + field: KProperty1, +) = yearMonth(field.simpTableField) + + +fun BaseTable.year( + field: KProperty1, +) = year(field.simpTableField) + +fun BaseTable.uuid( + field: KProperty1, +) = uuid(field.simpTableField) + +fun > BaseTable.enum( + field: KProperty1, + typeRef: TypeReference, +) = enum(field.simpTableField, typeRef) + +fun > BaseTable.enum( + field: KProperty1, + type: Class, +) = registerColumn(field.simpTableField, EnumSqlType(type)) + diff --git a/ts-database/src/main/kotlin/cn/tursom/database/TableField.kt b/ts-database/src/main/kotlin/cn/tursom/database/TableField.kt new file mode 100644 index 0000000..a8b8037 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/TableField.kt @@ -0,0 +1,247 @@ +/** + * SQL 访问增强工具,实现从属性到数据库字段的自动映射 + * @author 王景阔 + * 例: + * Files::name.tableField + * 可获得 Files 的 name 属性对应的字段名。 + */ + +@file:Suppress("unused") + +package cn.tursom.database + +import com.baomidou.mybatisplus.annotation.TableField +import com.baomidou.mybatisplus.annotation.TableName +import org.apache.ibatis.type.TypeHandler +import java.lang.reflect.Field +import java.lang.reflect.Modifier +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.companionObjectInstance +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.jvm.javaField +import kotlin.reflect.jvm.javaGetter + +/** + * 数据库访问增强接口 + * @author 王景阔 + * 设计上使用代理模式实现字段名缓存 + */ +interface TableField { + var tableName: String + val fieldMap: Map, String> + val simpFieldMap: Map, String> + val fullFieldMap: Map, String> + val properties: Array> + val allField: Array + val fullNameField: Array + val typeHandlerMap: Map, TypeHandler> + + //operator fun get(field: KProperty<*>): String = fieldMap[field] ?: field.tableField + operator fun get(field: KProperty1): String = fieldMap[field] ?: field.simpTableField +} + + +val Iterable>.filterNotExists + get() = filter { + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false + } + +@get:JvmName("filterNotExistsPair") +val Iterable, *>>.filterNotExists + get() = filter { (it, _) -> + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false + } + +@get:JvmName("filterNotExistsKProperty") +val Iterable>.filterNotExists + get() = filter { + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false + } + +@get:JvmName("filterNotExistsKPropertyPair") +val Iterable, *>>.filterNotExists + get() = filter { (it, _) -> + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false + } + +val String.sqlName: String + get() { + val sb = StringBuilder() + val iterator = iterator() + sb.append(iterator.nextChar().toLowerCase()) + iterator.forEach { + if (it.isUpperCase()) { + sb.append('_') + sb.append(it.toLowerCase()) + } else { + sb.append(it) + } + } + return sb.toString() + } + +val KClass<*>.tableName: String get() = findAnnotation()?.value ?: simpleName!!.sqlName +val Class<*>.tableName: String get() = getAnnotation(TableName::class.java)?.value ?: simpleName.sqlName +val KProperty<*>.tableFieldName: String? get() = javaField?.getAnnotation(TableField::class.java)?.value +val KProperty<*>.simpTableField: String get() = tableFieldName ?: name.sqlName +val KProperty<*>.selectionTableField: String + get() = tableFieldName?.let { if (it.isNotEmpty()) "$it as ${name.sqlName}" else null } ?: name.sqlName + +inline val KProperty1.tableField: String + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + companion[this] + } else { + selectionTableField + } + } + +inline val KProperty1.fullTableField: String + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + companion.fullFieldMap[this] ?: "${companion.tableName}.${companion[this]}" + } else { + "${T::class.tableName}.$selectionTableField" + } + } + +val KProperty<*>.fullTableField: String + get() { + val kotlin = (javaGetter?.declaringClass ?: javaField?.declaringClass)?.kotlin!! + return "${kotlin.tableName}.$selectionTableField" + } + +val Field.tableField: String + get() { + val tableField = getAnnotation(TableField::class.java) + return tableField?.value?.let { if (it.isNotEmpty()) "$it as ${name.sqlName}" else null } ?: name.sqlName + } + +val KProperty<*>.directTableField: String + get() = simpTableField + +inline val KProperty1.directTableField: String + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + companion.simpFieldMap[this] ?: simpTableField + } else { + simpTableField + } + } + +inline val Array>.directTableField: Array get() = asList().directTableField +inline val Collection>.directTableField: Array + get() { + val companion = T::class.companionObjectInstance + val fieldList = arrayOfNulls(size) + filterNotExists.forEach { + if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + companion.simpFieldMap[it] ?: it.simpTableField + } else { + it.simpTableField + } + } + @Suppress("UNCHECKED_CAST") + return fieldList as Array + } + +val Field.directTableField: String + get() { + val tableField = getAnnotation(TableField::class.java) + return tableField?.value?.ifEmpty { null } ?: name.sqlName + } + +inline val Array>.tableField: Array get() = asList().tableField +inline val Collection>.tableField: Array + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + filterNotExists.map { companion[it] } + } else { + filterNotExists.map { it.simpTableField } + }.toTypedArray() + } + +inline val Map, *>.tableField: Map + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + mapKeys { companion.simpFieldMap[it.key] ?: it.key.directTableField } + } else { + mapKeys { it.key.directTableField } + } + } + +inline val Array, *>>.tableField: Map get() = asList().tableField +inline val Collection, *>>.tableField: Map + get() { + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + filterNotExists.associate { (companion.simpFieldMap[it.first] ?: it.first.directTableField) to it.second } + } else { + filterNotExists.associate { it.first.directTableField to it.second } + } + } + + +val Array, *>>.fullTableField: Map get() = asList().fullTableField +val Collection, *>>.fullTableField: Map + get() { + val map = HashMap(size) + filterNotExists.forEach { (property, value) -> + map[property.fullTableField] = value + } + return map + } + +val Array>.fullTableField: Array get() = asList().fullTableField + +@get:JvmName("getKPropertyFullTableField") +val Collection>.fullTableField: Array + get() = filterNotExists.map { it.fullTableField }.toTypedArray() + + +inline val Array>.fullTableField: Array get() = asList().fullTableField +inline val Collection>.fullTableField: Array + get() { + val tableName = T::class.tableName + val companion = T::class.companionObjectInstance + return if (companion is cn.tursom.database.TableField<*>) { + @Suppress("UNCHECKED_CAST") + companion as cn.tursom.database.TableField + filterNotExists.map { "$tableName.${companion[it]}" } + } else { + filterNotExists.map { "$tableName.${it.simpTableField}" } + }.toTypedArray() + } diff --git a/ts-database/src/main/kotlin/cn/tursom/database/TableFieldImpl.kt b/ts-database/src/main/kotlin/cn/tursom/database/TableFieldImpl.kt new file mode 100644 index 0000000..691c1e3 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/TableFieldImpl.kt @@ -0,0 +1,69 @@ +package cn.tursom.database + +import cn.tursom.core.uncheckedCast +import cn.tursom.log.impl.Slf4jImpl +import org.apache.ibatis.type.TypeHandler +import java.lang.reflect.Modifier +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.javaField +import kotlin.reflect.jvm.jvmName + +/** + * 自动注入表单名称映射 + * @author 王景阔 + * 实现使用 类名[属性对象] 的方式来获取数据库属性名 + * 同时为 KProperty<*>.tableField 实现缓存加速 + */ +open class TableFieldImpl(clazz: KClass<*>? = null) : TableField { + companion object : Slf4jImpl() + + final override var tableName: String + + @Transient + final override val fieldMap = HashMap, String>() + final override val simpFieldMap = HashMap, String>() + final override val fullFieldMap = HashMap, String>() + + @Transient + final override val allField: Array + final override val fullNameField: Array + final override val properties: Array> + override val typeHandlerMap = HashMap, TypeHandler>() + + init { + if (clazz == null && this.javaClass == TableFieldImpl::class.java) { + throw NotImplementedError("需提供解析类") + } + @Suppress("UNCHECKED_CAST") + (clazz ?: this.javaClass.kotlin.run { + if (isCompanion) { + java.classLoader.loadClass(jvmName.dropLast(10)).kotlin + } else { + this + } + }).also { + tableName = it.tableName + }.memberProperties + .uncheckedCast>>() + .filter { + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false + } + .forEach { + val simpTableField = it.simpTableField + trace("mapping {}::{}", tableName, simpTableField) + simpFieldMap[it] = simpTableField + fieldMap[it] = it.selectionTableField + fullFieldMap[it] = "$tableName.${it.name.sqlName}" + it.findAnnotation()?.typeHandler + } + properties = fieldMap.keys.toTypedArray().uncheckedCast() + allField = fieldMap.values.toTypedArray() + fullNameField = allField.map { "$tableName.$it" }.toTypedArray() + } +} diff --git a/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapter.kt new file mode 100644 index 0000000..55ef26d --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapter.kt @@ -0,0 +1,25 @@ +package cn.tursom.database + +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 + +/** + * 将属性转化为表列的适配器 + */ +interface TypeAdapter { + /** + * 该适配器的优先级,优先级越高则越优先匹配 + * 同等优先级先注册者先匹配 + */ + val level: Int get() = 0 + + /** + * 注册列 + * 如果失败则返回null + */ + fun register( + table: BaseTable, + field: KProperty1, + ): Column? +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapterFactory.kt b/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapterFactory.kt new file mode 100644 index 0000000..ffd5891 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/TypeAdapterFactory.kt @@ -0,0 +1,76 @@ +package cn.tursom.database + +import cn.tursom.core.InstantAllocator +import cn.tursom.core.getClassByPackage +import cn.tursom.core.uncheckedCast +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.util.concurrent.ConcurrentSkipListMap +import java.util.concurrent.CopyOnWriteArraySet +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.isSubclassOf + +/** + * 注册类型适配器的工厂 + */ +object TypeAdapterFactory { + private val adapterMap = ConcurrentSkipListMap>>() + + init { + scanPackage(TypeAdapterFactory::class.java.`package`.name + ".typeadapter") + } + + private fun getAdapterQueue(level: Int): MutableCollection> { + var set = adapterMap[-level] + if (set == null) { + synchronized(this) { + adapterMap[-level] = CopyOnWriteArraySet() + set = adapterMap[-level]!! + } + } + return set!! + } + + /** + * 扫描包并注册适配器 + */ + fun scanPackage( + pkg: String, + classLoader: ClassLoader = this.javaClass.classLoader, + ) { + classLoader.getClassByPackage(pkg).forEach { + try { + val clazz = Class.forName(it).kotlin + if (clazz.isSubclassOf(TypeAdapter::class)) { + val adapter: TypeAdapter<*> = InstantAllocator[clazz].uncheckedCast() + registerAdapter(adapter) + } + } catch (e: Throwable) { + } + } + } + + /** + * 注册适配器实例 + */ + fun registerAdapter(adapter: TypeAdapter<*>) { + getAdapterQueue(adapter.level).add(adapter) + } + + fun register( + table: BaseTable<*>, + field: KProperty1<*, *>, + ): Column<*>? { + adapterMap.forEach { (_, queue) -> + queue.forEach { + val column = it.register(table.uncheckedCast(), field.uncheckedCast()) + if (column != null) { + return column + } + } + } + return null + } + + override fun toString() = adapterMap.toString() +} diff --git a/ts-database/src/main/kotlin/cn/tursom/database/WrapperEnhance.kt b/ts-database/src/main/kotlin/cn/tursom/database/WrapperEnhance.kt new file mode 100644 index 0000000..adb3802 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/WrapperEnhance.kt @@ -0,0 +1,332 @@ +/** + * QueryWrapper kotlin 化改造 + * @author 王景阔 + */ +@file:Suppress("unused") + +package cn.tursom.database + +import cn.tursom.core.uncheckedCast +import cn.tursom.database.annotations.Getter +import cn.tursom.log.impl.Slf4jImpl +import com.baomidou.mybatisplus.annotation.TableField +import com.baomidou.mybatisplus.core.conditions.AbstractWrapper +import com.baomidou.mybatisplus.core.conditions.ISqlSegment +import com.baomidou.mybatisplus.core.conditions.Wrapper +import com.baomidou.mybatisplus.core.conditions.interfaces.Compare +import com.baomidou.mybatisplus.core.conditions.interfaces.Func +import com.baomidou.mybatisplus.core.conditions.interfaces.Join +import com.baomidou.mybatisplus.core.conditions.query.Query +import com.baomidou.mybatisplus.core.conditions.update.Update +import com.baomidou.mybatisplus.core.toolkit.Constants +import java.lang.reflect.Field +import java.lang.reflect.Modifier +import java.util.* +import java.util.concurrent.atomic.AtomicInteger +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.isAccessible +import kotlin.reflect.jvm.javaField +import kotlin.reflect.jvm.javaGetter + +val logger = Slf4jImpl.getLogger("com.ddbes.pan.kit.jdbc") + +val select: Query<*, *, Any>.(Array) -> Any = Query<*, *, Any>::select + +@Suppress("UNCHECKED_CAST") +fun , Q> Query.select( + columns: Array, +): Children = (select as Query.(Array) -> Children)(columns) + +/** + * QueryWrapper().select(T::fieldName, value) + */ +inline fun > Query.select( + vararg columns: KProperty1, +): Children = select(columns.tableField) + +fun > Query.select( + vararg columns: KProperty<*>, +): Children = fullSelect(*columns) + +fun > Query.fullSelect( + vararg columns: KProperty<*>, +): Children = select(columns.fullTableField) + +/** + * QueryWrapper().eq(T::fieldName, value) + */ +inline fun > Compare.eq( + column: KProperty1, + value: Any, +): Children = eq(column.directTableField, value) + +fun > Compare.eq( + column: KProperty<*>, + value: Any, +): Children = eq(column.directTableField, value) + +inline fun > Compare.eq( + column: Pair, Any?>, +): Children = eq(column.first.directTableField, column.second) + +inline fun > Compare.eq( + vararg pair: Pair, Any?>, +): Children = allEq(pair.tableField) + +inline fun > Compare.eq( + pair: Collection, Any>>, +): Children = allEq(pair.tableField) + +fun Compare.eq(vararg pair: Pair, *>): Children = allEq(pair.fullTableField) + +inline fun > Compare.eq(entity: T): Children { + val eqs = LinkedList, Any>>() + entity::class.memberProperties.uncheckedCast>>().forEach { + it.isAccessible = true + eqs.add(it to (it(entity) ?: return@forEach)) + } + return eq(eqs) +} + +/** + * QueryWrapper().allEq(mapOf( + * T::fieldName1 to value1, + * T::fieldName2 to value2, + * ... + * )) + */ +inline fun > Compare.allEq(map: Map, *>): Children = + allEq(map.tableField) + +inline fun > Compare.allEq(vararg pair: Pair, *>): Children = + allEq(pair.tableField) + +fun Compare.allEq(vararg pair: Pair, *>): Children = + allEq(pair.fullTableField) + +fun Compare.allFullEq(vararg pair: Pair, *>): Children = + allEq(pair.fullTableField) + +inline fun > Compare.ne( + column: KProperty1, + value: Any?, +): Children = ne(column.directTableField, value) + +inline fun > Compare.gt( + column: KProperty1, + value: Any?, +): Children = gt(column.directTableField, value) + +inline fun > Compare.ge( + column: KProperty1, + value: Any?, +): Children = ge(column.directTableField, value) + +inline fun > Compare.lt( + column: KProperty1, + value: Any?, +): Children = lt(column.directTableField, value) + +inline fun > Compare.le( + column: KProperty1, + value: Any?, +): Children = le(column.directTableField, value) + +inline fun > Compare.between( + column: KProperty1, + val1: Any?, + val2: Any?, +): Children = between(column.directTableField, val1, val2) + +inline fun > Compare.notBetween( + column: KProperty1, + val1: Any?, + val2: Any?, +): Children = notBetween(column.directTableField, val1, val2) + +inline fun > Compare.like( + column: KProperty1, + value: Any?, +): Children = like(column.directTableField, value) + +inline fun > Compare.notLike( + column: KProperty1, + value: Any?, +): Children = notLike(column.directTableField, value) + +inline fun > Compare.likeLeft( + column: KProperty1, + value: Any?, +): Children = likeLeft(column.directTableField, value) + +inline fun > Compare.likeRight( + column: KProperty1, + value: Any?, +): Children = likeRight(column.directTableField, value) + +inline fun > Func.having( + column: KProperty1, + vararg value: Any?, +): Children = having(column.directTableField, value) + +inline fun > Func.isNull(column: KProperty1): Children = + isNull(column.directTableField) + +inline fun > Func.isNotNull(column: KProperty1): Children = + isNotNull(column.directTableField) + +inline fun > Func.`in`( + column: KProperty1, + value: Any?, +): Children = `in`(column.directTableField, value) + +inline fun > Func.`in`( + column: KProperty1, + value: Collection, +): Children = `in`(column.directTableField, value) + +inline fun > Func.`in`( + column: KProperty1, + vararg value: Any, +): Children = `in`(column.directTableField, value) + +inline fun > Func.notIn( + column: KProperty1, + value: Collection, +): Children = notIn(column.directTableField, value) + +inline fun > Func.notIn( + column: KProperty1, + vararg value: Any, +): Children = notIn(column.directTableField, value) + +inline fun > Func.inSql( + column: KProperty1, + value: String?, +): Children = inSql(column.directTableField, value) + +inline fun > Func.notInSql( + column: KProperty1, + value: String?, +): Children = notInSql(column.directTableField, value) + + +val groupBy: Func<*, String>.(Array) -> Any = Func<*, String>::groupBy +inline fun > Func.groupBy(column: KProperty1): Children = + groupBy(column.directTableField) + +@Suppress("UNCHECKED_CAST") +inline fun > Func.groupBy(vararg column: KProperty1): Children = + groupBy(column.directTableField) as Children + +val orderByAsc: Func<*, String>.(Array) -> Any = Func<*, String>::orderByAsc +inline fun > Func.orderByAsc(column: KProperty1): Children = + orderByAsc(column.directTableField) + +@Suppress("UNCHECKED_CAST") +inline fun > Func.orderByAsc(vararg column: KProperty1): Children = + orderByAsc(column.directTableField) as Children + +val orderByDesc: Func<*, String>.(Array) -> Any = Func<*, String>::orderByDesc +inline fun > Func.orderByDesc(column: KProperty1): Children = + orderByDesc(column.directTableField) + +@Suppress("UNCHECKED_CAST") +inline fun > Func.orderByDesc(vararg column: KProperty1): Children = + orderByDesc(column.directTableField) as Children + + +/** + * QueryWrapper() + * .xx() + * .xxx() + * ... + * .limit1() + */ +fun Join.limit1(): Children = last("LIMIT 1") + +inline fun > Update.set( + column: KProperty1, + value: Any?, +): Children { + if (column.javaField == null || Modifier.isTransient(column.javaField?.modifiers ?: Modifier.TRANSIENT) || + column.javaField?.getAnnotation(TableField::class.java)?.exist == false + ) { + return uncheckedCast() + } + val getter = column.findAnnotation() + val v = if (getter == null || !(value != null && getter.getterType.isInstance(value))) { + value + } else { + val getterMethod = column.javaGetter!!.declaringClass.getDeclaredMethod(getter.getter, getter.getterType.java) + getterMethod.isAccessible = true + getterMethod.invoke(null, value) + } + return set(column.directTableField, v) +} + +inline fun > Update.set(vararg values: Pair, Any?>): Children { + var children: Children? = null + values.forEach { (column, value) -> + set(column, value).let { + if (children == null) children = it + } + } + return children ?: uncheckedCast() +} + +inline fun > Update.set(value: T): Children { + var children: Children? = null + value::class.memberProperties + .uncheckedCast>>() + .filter { + it.javaField != null && + it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null && + !Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) && + it.javaField?.getAnnotation(TableField::class.java)?.exist != false + } + .forEach { property -> + property.isAccessible = true + set(property, property.get(value) ?: return@forEach).let { + if (children == null) children = it + } + } + return children ?: uncheckedCast() +} + +object Regexp : ISqlSegment { + override fun getSqlSegment(): String = "REGEXP" +} + +object WrapperEnhance : AbstractWrapper() { + override fun instance(): WrapperEnhance = this + private val paramNameSeqField: Field = + AbstractWrapper::class.java.getDeclaredField("paramNameSeq").apply { isAccessible = true } + + init { + initNeed() + } + + fun > regex(wrapper: W, column: String, value: Any): W { + wrapper.expression.add(ISqlSegment { columnToString(column) }, Regexp, ISqlSegment { + val genParamName = Constants.WRAPPER_PARAM + (paramNameSeqField.get(wrapper) as AtomicInteger).incrementAndGet() + wrapper.paramNameValuePairs[genParamName] = value + String.format(Constants.WRAPPER_PARAM_FORMAT, Constants.WRAPPER, genParamName) + }) + return wrapper + } +} + +fun > W.regex(column: String, value: Any): W = + WrapperEnhance.regex(this, column, value) + +inline fun > W.regex( + column: KProperty1, value: Any, +): W = WrapperEnhance.regex(this, column.directTableField, value) + +inline fun > W.regex( + column: KProperty1, regex: Regex, +): W = WrapperEnhance.regex(this, column.directTableField, regex.toString()) diff --git a/ts-database/src/main/kotlin/cn/tursom/database/annotations/Getter.kt b/ts-database/src/main/kotlin/cn/tursom/database/annotations/Getter.kt new file mode 100644 index 0000000..ae1a889 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/annotations/Getter.kt @@ -0,0 +1,10 @@ +package cn.tursom.database.annotations + +import kotlin.reflect.KClass + +/** + * 很抱歉我暂时做不到兼容 mybatis 的 TypeHandler,只能用这种方式凑合一下了 + */ +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.PROPERTY) +annotation class Getter(val getter: String, val getterType: KClass<*>) \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/annotations/Json.kt b/ts-database/src/main/kotlin/cn/tursom/database/annotations/Json.kt new file mode 100644 index 0000000..527209b --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/annotations/Json.kt @@ -0,0 +1,6 @@ +package cn.tursom.database.annotations + +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.PROPERTY) +annotation class Json \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BooleanAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BooleanAdapter.kt new file mode 100644 index 0000000..944f19a --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BooleanAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.boolean +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object BooleanAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Boolean::class) { + table.boolean(field) + } else { + null + } + } + + override fun toString() = "BooleanAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BytesAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BytesAdapter.kt new file mode 100644 index 0000000..40b0583 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/BytesAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.bytes +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object BytesAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == ByteArray::class) { + table.bytes(field) + } else { + null + } + } + + override fun toString() = "BytesAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DateAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DateAdapter.kt new file mode 100644 index 0000000..5b15816 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DateAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.jdbcDate +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.sql.Date +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object DateAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Date::class) { + table.jdbcDate(field) + } else { + null + } + } + + override fun toString() = "DateAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DoubleAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DoubleAdapter.kt new file mode 100644 index 0000000..3e4c39c --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/DoubleAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.double +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object DoubleAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Double::class) { + table.double(field) + } else { + null + } + } + + override fun toString() = "DoubleAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/EnumAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/EnumAdapter.kt new file mode 100644 index 0000000..436af5a --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/EnumAdapter.kt @@ -0,0 +1,28 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.core.uncheckedCast +import cn.tursom.database.TypeAdapter +import cn.tursom.database.simpTableField +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import me.liuwj.ktorm.schema.EnumSqlType +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.jvm.jvmErasure + +object EnumAdapter : TypeAdapter { + enum class EnumType + + override fun register(table: BaseTable, field: KProperty1): Column? { + val kClass = field.returnType.jvmErasure + return if (kClass.isSubclassOf(Enum::class)) { + table.registerColumn(field.simpTableField, EnumSqlType(kClass.java.uncheckedCast())) + .uncheckedCast() + } else { + null + } + } + + override fun toString() = "EnumAdapter" + +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/FloatAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/FloatAdapter.kt new file mode 100644 index 0000000..6c69b41 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/FloatAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.float +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object FloatAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Float::class) { + table.float(field) + } else { + null + } + } + + override fun toString() = "FloatAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/InstantAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/InstantAdapter.kt new file mode 100644 index 0000000..c465676 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/InstantAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.timestamp +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.time.Instant +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object InstantAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Instant::class) { + table.timestamp(field) + } else { + null + } + } + + override fun toString() = "InstantAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapter.kt new file mode 100644 index 0000000..9d7bc27 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.int +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object IntAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Int::class) { + table.int(field) + } else { + null + } + } + + override fun toString() = "IntAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapterAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapterAdapter.kt new file mode 100644 index 0000000..82cb7c2 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/IntAdapterAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.decimal +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.math.BigDecimal +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object IntAdapterAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == BigDecimal::class) { + table.decimal(field) + } else { + null + } + } + + override fun toString() = "IntAdapterAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/JsonAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/JsonAdapter.kt new file mode 100644 index 0000000..91e184a --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/JsonAdapter.kt @@ -0,0 +1,23 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.annotations.Json +import cn.tursom.database.json +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation + +object JsonAdapter : TypeAdapter { + override val level: Int get() = -16 + + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.findAnnotation() != null) { + table.json(field) + } else { + null + } + } + + override fun toString() = "JsonAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateAdapter.kt new file mode 100644 index 0000000..42c10b1 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.date +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.time.LocalDate +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object LocalDateAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == LocalDate::class) { + table.date(field) + } else { + null + } + } + + override fun toString() = "LocalDateAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateTimeAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateTimeAdapter.kt new file mode 100644 index 0000000..e246a49 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalDateTimeAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.datetime +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.time.LocalDateTime +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object LocalDateTimeAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == LocalDateTime::class) { + table.datetime(field) + } else { + null + } + } + + override fun toString() = "LocalDateTimeAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalTimeAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalTimeAdapter.kt new file mode 100644 index 0000000..759b0b0 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LocalTimeAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.time +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.time.LocalTime +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object LocalTimeAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == LocalTime::class) { + table.time(field) + } else { + null + } + } + + override fun toString() = "LocalTimeAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LongAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LongAdapter.kt new file mode 100644 index 0000000..8c65518 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/LongAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.long +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object LongAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == Long::class) { + table.long(field) + } else { + null + } + } + + override fun toString() = "LongAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/MonthDayAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/MonthDayAdapter.kt new file mode 100644 index 0000000..10e44be --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/MonthDayAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.monthDay +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.time.MonthDay +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object MonthDayAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == MonthDay::class) { + table.monthDay(field) + } else { + null + } + } + + override fun toString() = "MonthDayAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/StringAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/StringAdapter.kt new file mode 100644 index 0000000..b40aad0 --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/StringAdapter.kt @@ -0,0 +1,20 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.varchar +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object StringAdapter : TypeAdapter { + override fun register(table: BaseTable, field: KProperty1): Column? { + return if (field.returnType.jvmErasure == String::class) { + table.varchar(field) + } else { + null + } + } + + override fun toString() = "StringAdapter" +} \ No newline at end of file diff --git a/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/TimeAdapter.kt b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/TimeAdapter.kt new file mode 100644 index 0000000..c97935a --- /dev/null +++ b/ts-database/src/main/kotlin/cn/tursom/database/typeadapter/TimeAdapter.kt @@ -0,0 +1,21 @@ +package cn.tursom.database.typeadapter + +import cn.tursom.database.TypeAdapter +import cn.tursom.database.jdbcTime +import me.liuwj.ktorm.schema.BaseTable +import me.liuwj.ktorm.schema.Column +import java.sql.Time +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.jvmErasure + +object TimeAdapter : TypeAdapter