mirror of
https://github.com/tursom/TursomServer.git
synced 2025-01-30 14:20:07 +08:00
Merge remote-tracking branch 'origin/master' into master
This commit is contained in:
commit
eeacd926b2
@ -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<KotlinCompile>().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) {
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
53
ts-core/src/main/kotlin/cn/tursom/core/InstantAllocator.kt
Normal file
53
ts-core/src/main/kotlin/cn/tursom/core/InstantAllocator.kt
Normal file
@ -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<Class<*>, AllocateFunction>()
|
||||
|
||||
@Throws(NoSuchMethodException::class)
|
||||
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
|
||||
|
||||
@Throws(NoSuchMethodException::class)
|
||||
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
|
||||
|
||||
@Throws(NoSuchMethodException::class)
|
||||
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
|
||||
|
||||
@Throws(NoSuchMethodException::class)
|
||||
operator fun <T> get(clazz: Class<out T>, unsafe: Boolean = true): T {
|
||||
return when (allocateFunctionMap[clazz]) {
|
||||
null -> try {
|
||||
val newInstance = clazz.newInstance()
|
||||
allocateFunctionMap[clazz] = AllocateFunction.INSTANCE
|
||||
newInstance
|
||||
} catch (e: Exception) {
|
||||
val kClass = clazz.kotlin
|
||||
val objectInstance = kClass.objectInstance
|
||||
if (objectInstance != null) {
|
||||
allocateFunctionMap[clazz] = AllocateFunction.KOBJECT
|
||||
objectInstance
|
||||
} else if (unsafe) try {
|
||||
allocateFunctionMap[clazz] = AllocateFunction.UNSAFE
|
||||
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
|
||||
} catch (e: Exception) {
|
||||
allocateFunctionMap[clazz] = AllocateFunction.NONE
|
||||
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||
} else {
|
||||
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||
}
|
||||
}
|
||||
AllocateFunction.INSTANCE -> clazz.newInstance()
|
||||
AllocateFunction.UNSAFE -> if (unsafe) {
|
||||
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
|
||||
} else {
|
||||
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||
}
|
||||
AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!!
|
||||
AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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<Pair<Thread, ScheduledExecutorService>>()
|
||||
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<Thread, ScheduledExecutorService> {
|
||||
if (initCount.get() < threadCount) {
|
||||
initOne()
|
||||
}
|
||||
val pair = scheduledExecutorQueue.poll()
|
||||
scheduledExecutorQueue.add(pair)
|
||||
return pair
|
||||
}
|
||||
}
|
@ -1,12 +1,26 @@
|
||||
package cn.tursom.core
|
||||
|
||||
open class SimpThreadLocal<T>(private val new: () -> T) : ThreadLocal<T>() {
|
||||
override fun get(): T = super.get() ?: update()
|
||||
open class SimpThreadLocal<T : Any>(
|
||||
private val threadLocal: ThreadLocal<T?>? = null,
|
||||
val new: () -> T,
|
||||
) : ThreadLocal<T>() {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
@ -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
|
||||
}
|
@ -4,8 +4,8 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ThreadLocalSimpleDateFormat(
|
||||
val format: String = "YYYY-MM-dd'T'HH:mm:ssZZ"
|
||||
) : SimpThreadLocal<SimpleDateFormat>({
|
||||
val format: String = "YYYY-MM-dd'T'HH:mm:ssZZ",
|
||||
) : SimpThreadLocal<SimpleDateFormat>(null, {
|
||||
SimpleDateFormat(format)
|
||||
}) {
|
||||
fun format(date: Any) = get().format(date)
|
||||
|
@ -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 <T, R : Any> Iterable<T>.toSetNotNull(transform: (T) -> R?): Set<R> {
|
||||
}
|
||||
|
||||
|
||||
@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 <T> Any?.cast() = this as T
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
||||
inline fun <T> Any?.uncheckedCast() = this as T
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
||||
inline fun <reified T> Any?.castOrNull() = if (this is T) this else null
|
||||
|
||||
@ -126,7 +140,7 @@ inline fun <T> T?.checkNull(ifNull: () -> Exception): T {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.emptyToNull() = if (isEmpty()) null else this
|
||||
fun String.emptyToNull() = ifEmpty { null }
|
||||
|
||||
inline fun <reified T> getClazz() = T::class.java
|
||||
|
||||
@ -242,7 +256,7 @@ fun <A : Annotation, V : Any> A.changeAnnotationValue(field: KProperty1<A, V>, v
|
||||
val h = Proxy.getInvocationHandler(this)
|
||||
val memberValuesField = h.javaClass.getDeclaredField("memberValues")
|
||||
memberValuesField.isAccessible = true
|
||||
val memberValues = memberValuesField[h].cast<MutableMap<String, Any>>()
|
||||
val memberValues = memberValuesField[h].uncheckedCast<MutableMap<String, Any>>()
|
||||
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<Field>
|
||||
@ -295,6 +304,17 @@ val Class<*>.allFields: List<Field>
|
||||
return fieldList
|
||||
}
|
||||
|
||||
val Class<*>.allFieldsSequence: Sequence<Field>
|
||||
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<Method>
|
||||
return fieldList
|
||||
}
|
||||
|
||||
val Class<*>.allMethodsSequence: Sequence<Method>
|
||||
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<Class<*>>()
|
||||
Utils.ownerField.get(this)?.uncheckedCast<Class<*>>()
|
||||
} 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 <K : Any, V> Map<K?, V>.notNullKey get() = cast<Map<K, V>>()
|
||||
inline val <K, V : Any> Map<K, V?>.notNullValue get() = cast<Map<K, V>>()
|
||||
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = cast<Map<K, V>>()
|
||||
inline val <K : Any, V> Map<K?, V>.notNullKey get() = uncheckedCast<Map<K, V>>()
|
||||
inline val <K, V : Any> Map<K, V?>.notNullValue get() = uncheckedCast<Map<K, V>>()
|
||||
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = uncheckedCast<Map<K, V>>()
|
||||
|
||||
inline val <K : Any, V> Map<K?, V>.filterNullKey get() = filter { it.key != null }.notNullKey
|
||||
inline val <K, V : Any> Map<K, V?>.filterNullValue get() = filter { it.value != null }.notNullValue
|
||||
@ -442,7 +461,7 @@ val <T : Any> KClass<T>.allMemberProperties: List<KProperty1<T, *>>
|
||||
!it.java.isInterface
|
||||
}
|
||||
while (superClass != null) {
|
||||
propertiesList.addAll(superClass.memberProperties.cast())
|
||||
propertiesList.addAll(superClass.memberProperties.uncheckedCast())
|
||||
superClass = superClass.superclasses.firstOrNull {
|
||||
!it.java.isInterface
|
||||
}
|
||||
|
@ -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<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -15,6 +15,10 @@ tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives(tasks["kotlinSourcesJar"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
@ -24,7 +28,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -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 = "",
|
||||
)
|
||||
|
@ -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<*>,
|
||||
)
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
@ -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,
|
||||
)
|
@ -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<T> = KProperty1<T, Any?>
|
||||
|
||||
val Any.valueMap: Map<String, Any?>
|
||||
get() = if (this is Map<*, *>) {
|
||||
cast()
|
||||
} else {
|
||||
KPropertyValueMap(this)
|
||||
}
|
||||
|
||||
private val injectMapCache = ReadWriteMap<KClass<*>, ArrayMap<String, Property<*>?>>(SoftArrayMap(HashMap()))
|
||||
|
||||
val <T : Any> KClass<T>.injectMap: ArrayMap<String, Property<T>?>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = let {
|
||||
var valueMap = injectMapCache[it] as ArrayMap<String, Property<T>?>?
|
||||
if (valueMap == null) {
|
||||
val properties = it.memberProperties
|
||||
valueMap = ArrayMap(properties.size)
|
||||
(properties as Collection<Property<T>>).forEach { property ->
|
||||
property.isAccessible = true
|
||||
valueMap[property.name] = property
|
||||
}
|
||||
injectMapCache[it] = valueMap as ArrayMap<String, Property<*>?>
|
||||
}
|
||||
valueMap.copy()
|
||||
}
|
||||
|
||||
private val <T : Any> T.injectMap: ArrayMap<String, Property<T>?>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = (this::class as KClass<T>).injectMap
|
||||
|
||||
private val <T> Array<out Pair<Property<*>, Property<T>?>>.injectMap get() = iterator().injectMap
|
||||
private val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
|
||||
get() = let {
|
||||
val valueMap = ArrayMap<String, Property<T>?>()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
forEach { (k, field) ->
|
||||
field?.isAccessible = true
|
||||
valueMap[k.name] = field
|
||||
}
|
||||
//logger.trace("Iterator.injectMap: {}", valueMap)
|
||||
valueMap
|
||||
}
|
||||
|
||||
private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<T>?> = this::class
|
||||
.cast<KClass<T>>()
|
||||
.injectMap
|
||||
.also {
|
||||
if (clazz == null) return@also
|
||||
val clazzThis = this::class.java
|
||||
|
||||
fun import(relation: Relation, property: Property<T>) {
|
||||
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<T, Any?>, KProperty1<T, Any?> by property {
|
||||
override val setter: KMutableProperty1.Setter<T, Any?> 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<T>) {
|
||||
when (annotation) {
|
||||
is Relation -> import(annotation, property)
|
||||
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
|
||||
}
|
||||
}
|
||||
|
||||
this::class.memberProperties.cast<Collection<KProperty1<T, *>>>().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 : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<
|
||||
*/
|
||||
inline fun <reified T : Any, S : Any> List<S?>.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||
): List<T> {
|
||||
val list = ArrayList<T>(size)
|
||||
val memberMap = T::class.injectMap
|
||||
@ -131,25 +43,28 @@ inline fun <reified T : Any, S : Any> List<S?>.clone(
|
||||
}
|
||||
forEach {
|
||||
it ?: return@forEach
|
||||
val target = instance<T>(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 <reified T : Any> List<Any?>.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Property<T>?
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Property<T>?,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
fun <T : Any> List<Any?>.clone(
|
||||
target: T,
|
||||
vararg relation: Property<T>?
|
||||
vararg relation: Property<T>?,
|
||||
): T = clone(target, relation.iterator())
|
||||
|
||||
fun <T : Any> List<Any?>.clone(
|
||||
target: T,
|
||||
relation: Iterator<Property<T>?>
|
||||
relation: Iterator<Property<T>?>,
|
||||
): T = relation.mapIndexed { index, kProperty1 ->
|
||||
(kProperty1 ?: return@mapIndexed null).name to this[index]
|
||||
}.clone(target)
|
||||
@ -157,29 +72,30 @@ fun <T : Any> List<Any?>.clone(
|
||||
|
||||
/**
|
||||
* 新建并拷贝
|
||||
* @author 王景阔
|
||||
* 创建类型 T 的实例
|
||||
* 并将对象两个的所有同名字段拷贝进新建的实例中
|
||||
* @return 新建的实例
|
||||
* @param unsafe 是否允许使用 Unsafe 创建对象,unsafe 不需调用构造函数,可以在没有默认构造函数的情况下生成对象
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(instance<T>(unsafe)!!)
|
||||
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(InstantAllocator[T::class.java, unsafe])
|
||||
|
||||
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(instance(unsafe, clazz)!!)
|
||||
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(InstantAllocator[clazz, unsafe])
|
||||
|
||||
@JvmName("unsafeClone")
|
||||
inline fun <reified T : Any> Any.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Pair<String, Property<T>?>,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
inline fun <reified T : Any, S : Any> S.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
fun Any.cloneMap(): Map<in String, Any?> = when (this) {
|
||||
is Map<*, *> -> @Suppress("UNCHECKED_CAST") (this as Map<Any?, Any?>).mapKeys { it.key.toString() }
|
||||
is Map<*, *> -> uncheckedCast<Map<Any?, Any?>>().mapKeys { it.key.toString() }
|
||||
is Iterator<*> -> {
|
||||
val valueMap = HashMap<String, Any?>()
|
||||
(this as Iterator<Any?>).forEach {
|
||||
@ -201,22 +117,22 @@ fun <T : Any> Any.clone(target: T): T = apply { injectWithoutProperty(target) }.
|
||||
|
||||
fun <T : Any, S : Any> S.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<S>, Property<T>?>>
|
||||
iterator: Iterator<Pair<Property<S>, Property<T>?>>,
|
||||
): 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 <T : Any> Any.clone(
|
||||
target: T,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
vararg relation: Pair<String, Property<T>?>,
|
||||
): T = clone(target, relation.iterator())
|
||||
|
||||
@JvmName("unsafeClone")
|
||||
fun <T : Any> Any.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>
|
||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
||||
valueMap.clone(target, iterator, this::class)
|
||||
}
|
||||
@ -225,9 +141,9 @@ fun <T : Any> Any.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||
clazz: KClass<*>? = null
|
||||
clazz: KClass<*>? = null,
|
||||
): T {
|
||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
||||
val memberMap = target.injectMap(clazz)
|
||||
iterator.forEach { (k, v) ->
|
||||
memberMap[k] = v
|
||||
}
|
||||
@ -238,9 +154,9 @@ fun <T : Any> Map<in String, Any?>.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
||||
clazz: KClass<*>? = null
|
||||
clazz: KClass<*>? = null,
|
||||
): T {
|
||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
||||
val memberMap = target.injectMap(clazz)
|
||||
iterator.forEach { (k, v) ->
|
||||
memberMap[k.get(target)?.toString() ?: return@forEach] = v
|
||||
}
|
||||
@ -251,13 +167,13 @@ fun <T : Any> Map<in String, Any?>.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
||||
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 <T : Any> Any.checkPropertyClone(target: T, ifClone: () -> T): T =
|
||||
target
|
||||
}
|
||||
|
||||
//fun <T> Any.checkPropertyClone(targetClass: KClass<out Any>, ifClone: () -> T): T {
|
||||
// if (targetClass.findAnnotation<NoPropertyClone>()?.classList?.contains(this::class) != true)
|
||||
// ifClone()
|
||||
//}
|
||||
|
||||
fun <T : Any> Any.injectWithoutProperty(target: T): T {
|
||||
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
|
||||
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<Collection<KProperty1<Any, *>>>()
|
||||
.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 <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String?, Property<T>?>>
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
@JvmName("injectMap")
|
||||
fun <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
fun <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Map<in String, Any?>.p2pInject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>
|
||||
): 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 <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String, Property<T>?>>
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Any.inject(target: T, property: Property<T>) {
|
||||
//logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
|
||||
when (property) {
|
||||
is KMutableProperty1<*, *> -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
property as KMutableProperty1<T, Any?>
|
||||
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 : Any> T.read(source: Any?): T = source?.clone(this) ?: this
|
||||
|
||||
fun <T : Any, S : Any> T.read(
|
||||
source: S?,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): T = source?.clone(this, relation.iterator()) ?: this
|
||||
|
||||
fun <T : Any> T.read(
|
||||
source: Map<in String, Any?>?,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
): T = source?.clone(this, relation.iterator()) ?: this
|
||||
|
||||
|
||||
fun <T : Any> T.p2pRead(
|
||||
source: Map<in String, Any?>?,
|
||||
vararg relation: Pair<Property<T>, Property<T>?>
|
||||
): T {
|
||||
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
|
||||
return source?.p2pInject(this, relation.iterator()) ?: this
|
||||
}
|
||||
|
||||
fun <T : Any> T.p2pRead(
|
||||
source: Map<in String, Any?>?
|
||||
): T {
|
||||
source ?: return this
|
||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
||||
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 : Any> T.p2pRead(
|
||||
source: Any?
|
||||
): T {
|
||||
source ?: return this
|
||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
||||
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 <T : Any, S : Any> List<T>.read(
|
||||
source: List<S>,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): List<T> {
|
||||
val memberMap = this[0].injectMap as MutableMap<String, Property<T>?>
|
||||
relation.forEach { (k, v) ->
|
||||
memberMap[k.name] = v
|
||||
}
|
||||
return source.mapIndexed { index, it -> it.inject(this[index], memberMap.iterator()) }
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> read(vararg values: Any, unsafe: Boolean = true): T {
|
||||
val instance = instance<T>(unsafe)!!
|
||||
values.forEach {
|
||||
it.clone(instance)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> read(value: Any, unsafe: Boolean = true): T = value.clone(unsafe)
|
||||
|
||||
fun <T : Any> T.readWithoutProperty(vararg values: Any): T {
|
||||
values.forEach {
|
||||
it.injectWithoutProperty(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
|
||||
|
||||
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T? = try {
|
||||
clazz.newInstance()!!
|
||||
} catch (e: Exception) {
|
||||
if (unsafe) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Unsafe.unsafe.allocateInstance(clazz) as T?
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) -> Pair<K, V>?): Map<K, V> {
|
||||
val map = ArrayMap<K, V>()
|
||||
@ -502,6 +195,113 @@ inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) ->
|
||||
return map
|
||||
}
|
||||
|
||||
fun <T : Any> T.mapRead(map: Map<in String, Any?>, key: KProperty1<T, *>): T {
|
||||
return read(map[key.get(this)?.toString() ?: return this] ?: return this)
|
||||
fun <T : Any, F : Any?> T.set(field: KProperty1<T, F>, value: F): T {
|
||||
(value as Any?)?.inject(this, field as Property<T>)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : Any> 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 : Any> T.deepClone(clonedMap: MutableMap<Any, Any>): T =
|
||||
clonedMap[this]?.uncheckedCast<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()
|
||||
is Array<*> -> {
|
||||
val instance = java.lang.reflect.Array.newInstance(javaClass.componentType, size).uncheckedCast<Array<Any?>>()
|
||||
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<Any, Int>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, Any?>
|
||||
get() = if (this is Map<*, *>) {
|
||||
uncheckedCast()
|
||||
} else {
|
||||
KPropertyValueMap(this)
|
||||
}
|
||||
|
||||
private val injectMapCache = SoftArrayMap<KClass<*>, Map<String, Property<*>?>>(ConcurrentHashMap())
|
||||
|
||||
val <T : Any> KClass<T>.injectMap: MutableMap<String, Property<T>?>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() {
|
||||
var injectMap = injectMapCache[this] as Map<String, Property<T>?>?
|
||||
if (injectMap == null) {
|
||||
injectMap = allMemberProperties.associateByTo(HashMap()) { property ->
|
||||
property.isAccessible = true
|
||||
property.name
|
||||
}
|
||||
injectMapCache[this] = injectMap as Map<String, Property<*>?>
|
||||
}
|
||||
return HashMap(injectMap)
|
||||
}
|
||||
|
||||
internal val <T : Any> T.injectMap: MutableMap<String, Property<T>?>
|
||||
get() = this::class.uncheckedCast<KClass<T>>().injectMap
|
||||
|
||||
internal val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
|
||||
get() = let {
|
||||
val valueMap = HashMap<String, Property<T>?>()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
forEach { (k, field) ->
|
||||
field?.isAccessible = true
|
||||
valueMap[k.name] = field
|
||||
}
|
||||
logger.trace("Iterator.injectMap: {}", valueMap)
|
||||
valueMap
|
||||
}
|
||||
|
||||
internal fun <T : Any> T.injectMap(targetClazz: KClass<*>?): MutableMap<String, Property<T>?> = this::class
|
||||
.uncheckedCast<KClass<T>>()
|
||||
.injectMap
|
||||
.also { injectMap ->
|
||||
if (targetClazz == null) return@also
|
||||
val clazzThis = this::class.java
|
||||
|
||||
fun import(relation: Relation, property: Property<T>) {
|
||||
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<T, Any?>, KProperty1<T, Any?> by property {
|
||||
override val setter: KMutableProperty1.Setter<T, Any?>
|
||||
get() = object : KMutableProperty1.Setter<T, Any?>, KCallable<Unit> 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<Any?> 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<T>) {
|
||||
when (annotation) {
|
||||
is Relation -> import(annotation, property)
|
||||
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
|
||||
}
|
||||
}
|
||||
|
||||
this::class.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>().forEach { property ->
|
||||
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
|
||||
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
|
||||
parseAnnotation(annotation, property)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> Any.injectWithoutProperty(target: T): T {
|
||||
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
|
||||
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<Collection<KProperty1<Any, *>>>()
|
||||
.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 <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String?, Property<T>?>>,
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
@JvmName("injectMap")
|
||||
fun <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
fun <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||
): 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 <T : Any> Map<in String, Any?>.p2pInject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
||||
): 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 <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String, Property<T>?>>,
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Any.inject(target: T, property: Property<T>) {
|
||||
logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
|
||||
when (property) {
|
||||
is KMutableProperty1<*, *> -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
property as KMutableProperty1<T, Any?>
|
||||
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 <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
|
||||
|
||||
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T = InstantAllocator[clazz, unsafe]
|
||||
|
||||
fun <T> unsafeInstance(clazz: Class<T>, unsafe: Boolean = true): T? = if (unsafe) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Unsafe.unsafe.allocateInstance(clazz) as T?
|
||||
} else {
|
||||
null
|
||||
}
|
@ -24,7 +24,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@ -149,7 +149,7 @@ open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
override fun setValue(newValue: V): V = value.also { value = newValue }
|
||||
override fun compareTo(other: K): Int {
|
||||
return if (key is Comparable<*>) {
|
||||
key.cast<Comparable<K>>().compareTo(other)
|
||||
key.uncheckedCast<Comparable<K>>().compareTo(other)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
interface AsyncIterator<T> {
|
||||
/**
|
@ -1,11 +1,11 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
class DefaultValueMap<K, V>(
|
||||
private val map: Map<K, V?>,
|
||||
private val defaultValue: (K) -> V
|
||||
) : Map<K, V> by map.cast() {
|
||||
private val defaultValue: (K) -> V,
|
||||
) : Map<K, V> by map.uncheckedCast() {
|
||||
override val entries: Set<Map.Entry<K, V>> get() = Entry()
|
||||
override val values: Collection<V> get() = Values()
|
||||
|
||||
@ -21,8 +21,8 @@ class DefaultValueMap<K, V>(
|
||||
}
|
||||
|
||||
inner class Entry(
|
||||
private val entries: Set<Map.Entry<K, V?>> = map.entries
|
||||
) : Set<Map.Entry<K, V>> by entries.cast() {
|
||||
private val entries: Set<Map.Entry<K, V?>> = map.entries,
|
||||
) : Set<Map.Entry<K, V>> 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<Map.Entry<K, V>> = EntryIterator()
|
||||
@ -32,7 +32,7 @@ class DefaultValueMap<K, V>(
|
||||
private var next: Map.Entry<K, V>? = 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<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
inner class Values(
|
||||
private val values: Collection<V?> = map.values
|
||||
) : Collection<V> by values.cast() {
|
||||
private val values: Collection<V?> = map.values,
|
||||
) : Collection<V> 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<V> = ValuesIterator()
|
||||
@ -61,7 +61,7 @@ class DefaultValueMap<K, V>(
|
||||
|
||||
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<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
class DefaultValueMutableMap<K, V>(
|
||||
private val map: MutableMap<K, V?>,
|
||||
private val defaultValue: (K) -> V
|
||||
) : MutableMap<K, V> by map.cast() {
|
||||
private val defaultValue: (K) -> V,
|
||||
) : MutableMap<K, V> by map.uncheckedCast() {
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = Entry()
|
||||
override val values: MutableCollection<V> get() = Values()
|
||||
|
||||
@ -19,19 +19,19 @@ class DefaultValueMutableMap<K, V>(
|
||||
}
|
||||
|
||||
inner class Entry(
|
||||
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries
|
||||
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.cast() {
|
||||
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries,
|
||||
) : MutableSet<MutableMap.MutableEntry<K, V>> 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<MutableMap.MutableEntry<K, V>> = EntryIterator()
|
||||
|
||||
inner class EntryIterator(
|
||||
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator()
|
||||
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.cast() {
|
||||
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator(),
|
||||
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.uncheckedCast() {
|
||||
private var next: Map.Entry<K, V>? = 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<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
inner class Values(
|
||||
private val values: MutableCollection<V?> = map.values
|
||||
) : MutableCollection<V> by values.cast() {
|
||||
private val values: MutableCollection<V?> = map.values,
|
||||
) : MutableCollection<V> 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<V> = ValuesIterator()
|
||||
|
||||
inner class ValuesIterator(
|
||||
private val iterator: MutableIterator<V?> = values.iterator()
|
||||
) : MutableIterator<V> by iterator.cast() {
|
||||
private val iterator: MutableIterator<V?> = values.iterator(),
|
||||
) : MutableIterator<V> 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<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, Any?> {
|
||||
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
||||
var map = propertiesMapCache[clazz]
|
||||
if (map == null) {
|
||||
map = clazz.memberProperties.cast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
||||
properties.forEach {
|
||||
it.isAccessible = true
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@ -17,8 +17,8 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
|
||||
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
|
||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().uncheckedCast()
|
||||
override val values: MutableCollection<V> get() = arrValue.asList().uncheckedCast<MutableList<V>>().subList(0, end)
|
||||
|
||||
/**
|
||||
* @param key 查找的键
|
||||
@ -59,7 +59,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
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<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
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<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (end <= 0) {
|
||||
null
|
||||
} else {
|
||||
arrValue[0].cast()
|
||||
arrValue[0].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arr[index].cast()
|
||||
arr[index].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arrValue[index].cast()
|
||||
arrValue[index].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,10 +194,10 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
val map: ParallelArrayMap<K, V>,
|
||||
val index: Int
|
||||
) : MutableMap.MutableEntry<K, V> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* 当从上一级 MutableDelegatedField 获得到空值时
|
||||
* 自动调用updateValue方法更新值
|
||||
*/
|
||||
class AutoUpdatableMutableDelegatedField<in T, V : Any>(
|
||||
override val delegatedField: MutableDelegatedField<T, V?>,
|
||||
val updateValue: T.(property: KProperty<*>) -> V,
|
||||
) : MutableDelegatedField<T, V> by delegatedField.uncheckedCast(),
|
||||
DecoratorMutableDelegatedField<T, V?> {
|
||||
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 <T, V : Any> MutableDelegatedField<T, V?>.autoUpdate(
|
||||
updateValue: T.(property: KProperty<*>) -> V,
|
||||
): MutableDelegatedField<T, V> {
|
||||
return AutoUpdatableMutableDelegatedField(this, updateValue)
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface DecoratorDelegateProvider<in T, out V> :
|
||||
DelegateProvider<T, DelegatedField<T, V>>,
|
||||
DecoratorDelegatedField<T, V> {
|
||||
override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): DelegatedField<T, V> = delegatedField
|
||||
override operator fun provideDelegate(
|
||||
thisRef: T,
|
||||
prop: KProperty<*>,
|
||||
): DelegatedField<T, V> = delegatedField
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
interface DecoratorDelegatedField<in T, out V> {
|
||||
val delegatedField: DelegatedField<T, V>
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@ -7,5 +7,5 @@ interface DecoratorMutableDelegateProvider<in T, V> :
|
||||
//DecoratorProvideDelegate<T, V>,
|
||||
DecoratorMutableDelegatedField<T, V> {
|
||||
override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): MutableDelegatedField<T, V> =
|
||||
mutableDelegatedField
|
||||
delegatedField
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
interface DecoratorMutableDelegatedField<in T, V> : DecoratorDelegatedField<T, V> {
|
||||
override val delegatedField: MutableDelegatedField<T, V>
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
@ -0,0 +1,8 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
interface DelegatedFieldAttachmentKey<V> {
|
||||
operator fun get(delegatedField: DelegatedField<*, *>) = delegatedField[this]
|
||||
operator fun get(property0: KProperty0<*>) = property0.getDelegatedAttachmentValue(this)
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class ExecutorMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
private val executor: Executor,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<in T, V : Any>(
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
val expireMS: Long,
|
||||
) : MutableDelegatedField<T, V?> by delegatedField.uncheckedCast(),
|
||||
DecoratorMutableDelegatedField<T, V> {
|
||||
|
||||
@Volatile
|
||||
private var setTime: Long = 0L
|
||||
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V? {
|
||||
return if (System.currentTimeMillis() - setTime < expireMS) {
|
||||
delegatedField.uncheckedCast<MutableDelegatedField<T, V?>>().getValue(thisRef, property)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V?) {
|
||||
if (value != null) {
|
||||
delegatedField.setValue(value)
|
||||
setTime = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, V : Any> MutableDelegatedField<T, V>.expirable(
|
||||
expireTime: Long,
|
||||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS,
|
||||
): MutableDelegatedField<T, V?> {
|
||||
return ExpirableMutableDelegatedField(this, timeUnit.toMillis(expireTime))
|
||||
}
|
||||
|
||||
@JvmName("expirableTV?")
|
||||
fun <T, V : Any> MutableDelegatedField<T, V?>.expirable(
|
||||
expireTime: Long,
|
||||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS,
|
||||
): MutableDelegatedField<T, V?> {
|
||||
return ExpirableMutableDelegatedField(uncheckedCast(), timeUnit.toMillis(expireTime))
|
||||
}
|
||||
|
@ -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<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
private val filter: T.(old: V, new: V) -> Boolean,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
companion object Key : DelegatedFieldAttachmentKey<Boolean>
|
||||
|
||||
private var filterResult = false
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): 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<in T, V>(
|
||||
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<in T, V>(
|
||||
if (!filterResult) {
|
||||
return
|
||||
}
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
delegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class GetterMutableDelegatedField<in T, V>(
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
private val getter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V,
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = delegatedField.getter(thisRef, property)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
@ -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<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
private val lock: Lock = ReentrantLock(),
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
open class MutableDelegatedFieldValue<in T, V>(
|
||||
private var initValue: V
|
||||
private var initValue: V,
|
||||
) : MutableDelegatedField<T, V> {
|
||||
override fun getValue(): V = initValue
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = initValue
|
@ -0,0 +1,27 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class NotNullDelegatedField<in T, out V : Any>(
|
||||
override val delegatedField: DelegatedField<T, V?>,
|
||||
val ifNull: () -> Nothing = { throw NullPointerException() },
|
||||
) : DelegatedField<T, V> by delegatedField.uncheckedCast(), DecoratorDelegatedField<T, V?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class NotNullMutableDelegatedField<in T, V : Any>(
|
||||
override val delegatedField: MutableDelegatedField<T, V?>,
|
||||
val ifNull: () -> Nothing = { throw NullPointerException() },
|
||||
) : MutableDelegatedField<T, V> by delegatedField.uncheckedCast(), DecoratorMutableDelegatedField<T, V?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
private val readWriteLock: ReadWriteLock = ReentrantReadWriteLock(),
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
constructor(
|
||||
initValue: V,
|
||||
readWriteLock: ReadWriteLock = ReentrantReadWriteLock(),
|
||||
@ -19,7 +19,7 @@ class ReadWriteLockMutableDelegatedField<in T, V>(
|
||||
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<in T, V>(
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<in T, V>(
|
||||
private val receiver: T,
|
||||
private val field: Field,
|
||||
) : MutableDelegatedField<T, V> {
|
||||
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 : Any, V> T.superField(
|
||||
fieldName: String,
|
||||
): MutableDelegatedField<T, V> {
|
||||
return ReflectionDelegatedField(this, this.javaClass.getFieldForAll(fieldName)!!)
|
||||
}
|
||||
|
||||
fun <T, V> T.field(
|
||||
field: Field,
|
||||
): MutableDelegatedField<T, V> {
|
||||
return ReflectionDelegatedField(this, field)
|
||||
}
|
||||
|
||||
fun <T, V> T.field(
|
||||
field: Field,
|
||||
type: V,
|
||||
): MutableDelegatedField<T, V> {
|
||||
return ReflectionDelegatedField(this, field)
|
||||
}
|
||||
|
||||
inline fun <T, V> T.field(
|
||||
field: Field,
|
||||
type: () -> V,
|
||||
): MutableDelegatedField<T, V> {
|
||||
return ReflectionDelegatedField(this, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.delegation
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
class SetterDelegatedField<T, V>(
|
||||
override val delegatedField: DelegatedField<T, V>,
|
@ -0,0 +1,12 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class SetterMutableDelegatedField<T, V>(
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
val setter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>, value: V) -> Unit,
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
delegatedField.setter(thisRef, property, value)
|
||||
}
|
||||
}
|
@ -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<in T, V : Any>(
|
||||
private val threadLocal: SimpThreadLocal<V>,
|
||||
) : MutableDelegatedField<T, V> {
|
||||
constructor(new: () -> V) : this(SimpThreadLocal(new = new))
|
||||
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): 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<SimpThreadLocal<*>> {
|
||||
fun <T : Any> getKey() = this.uncheckedCast<DelegatedFieldAttachmentKey<SimpThreadLocal<T>>>()
|
||||
fun <T : Any> getKey(property: KProperty0<T>) =
|
||||
this.uncheckedCast<DelegatedFieldAttachmentKey<SimpThreadLocal<T>>>()
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
class ThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: ThreadLocal<V?> = ThreadLocal(),
|
||||
) : MutableDelegatedField<T, V?> {
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): 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<ThreadLocal<*>> {
|
||||
fun <T> getKey() = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
fun <T> getKey(property: KProperty0<T>) = this.uncheckedCast<DelegatedFieldAttachmentKey<ThreadLocal<T>>>()
|
||||
}
|
||||
}
|
@ -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 <V> KProperty0<V>.getOwnerDelegated: DelegatedField<*, V>?
|
||||
get() = getDelegate(receiver, name).castOrNull()
|
||||
get() = getDelegate(receiver, name).castOrNull()
|
||||
|
||||
/**
|
||||
* 获取委托过后的值
|
||||
* 不会触发getter方法
|
||||
*/
|
||||
val <V> KProperty0<V>.getDelegatedValue: V?
|
||||
get() {
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
return delegate?.castOrNull<DelegatedField<*, V>>()?.getValue()
|
||||
}
|
||||
get() {
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
return delegate?.castOrNull<DelegatedField<*, V>>()?.getValue()
|
||||
}
|
||||
|
||||
fun <V> KProperty0<*>.getDelegatedAttachmentValue(key: DelegatedFieldAttachmentKey<V>): V? {
|
||||
val delegated = getOwnerDelegated ?: return null
|
||||
return delegated[key]
|
||||
}
|
||||
|
||||
operator fun <V> KProperty0<*>.get(key: DelegatedFieldAttachmentKey<V>): V? = getDelegatedAttachmentValue(key)
|
||||
|
||||
fun <V> KProperty0<V>.setDelegatedValue(value: V): Boolean {
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
delegate.castOrNull<MutableDelegatedField<*, V>>()?.setValue(value) ?: return false
|
||||
return true
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
delegate.castOrNull<MutableDelegatedField<*, V>>()?.setValue(value) ?: return false
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,50 +57,74 @@ fun <V> KProperty0<V>.setDelegatedValue(value: V): Boolean {
|
||||
*/
|
||||
fun <T, V> T.delegated(value: V): MutableDelegatedField<T, V> = MutableDelegatedFieldValue(value)
|
||||
fun <T, V> T.delegated(@Suppress("UNUSED_PARAMETER") target: T, value: V): MutableDelegatedField<T, V> =
|
||||
MutableDelegatedFieldValue(value)
|
||||
MutableDelegatedFieldValue(value)
|
||||
|
||||
val <V> KProperty0<V>.delegated: DelegatedField<Any, V> get() = KPropertyDelegatedField(this)
|
||||
val <V> KMutableProperty0<V>.delegated: MutableDelegatedField<Any, V> get() = KPropertyMutableDelegatedField(this)
|
||||
val <V : Any> KProperty0<V?>.delegatedNotNull get() = delegated.notNull
|
||||
val <V : Any> KMutableProperty0<out V?>.delegatedNotNull: MutableDelegatedField<Any, V> get() = delegated.notNull
|
||||
fun <V : Any> KProperty0<V?>.delegatedNotNull(ifNull: () -> Nothing) = delegated.notNull(ifNull)
|
||||
fun <V : Any> KMutableProperty0<out V?>.delegatedNotNull(ifNull: () -> Nothing): MutableDelegatedField<Any, V> =
|
||||
delegated.notNull(ifNull)
|
||||
|
||||
val <T, V : Any> DelegatedField<T, V?>.notNull: DelegatedField<T, V> get() = NotNullDelegatedField(this)
|
||||
val <T, V : Any> MutableDelegatedField<T, out V?>.notNull: MutableDelegatedField<T, V>
|
||||
get() = NotNullMutableDelegatedField(cast())
|
||||
get() = NotNullMutableDelegatedField(uncheckedCast())
|
||||
|
||||
fun <T, V : Any> DelegatedField<T, V?>.notNull(ifNull: () -> Nothing): DelegatedField<T, V> =
|
||||
NotNullDelegatedField(this, ifNull)
|
||||
|
||||
fun <T, V : Any> MutableDelegatedField<T, out V?>.notNull(ifNull: () -> Nothing): MutableDelegatedField<T, V> =
|
||||
NotNullMutableDelegatedField(uncheckedCast(), ifNull)
|
||||
|
||||
val <T, V> MutableDelegatedField<T, V>.locked: MutableDelegatedField<T, V> get() = LockMutableDelegatedField(this)
|
||||
fun <T, V> MutableDelegatedField<T, V>.locked(lock: Lock = ReentrantLock()): MutableDelegatedField<T, V> =
|
||||
LockMutableDelegatedField(this, lock)
|
||||
LockMutableDelegatedField(this, lock)
|
||||
|
||||
val <T, V> MutableDelegatedField<T, V>.readWriteLocked: MutableDelegatedField<T, V>
|
||||
get() = ReadWriteLockMutableDelegatedField(this)
|
||||
get() = ReadWriteLockMutableDelegatedField(this)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.readWriteLocked(readWriteLock: ReadWriteLock = ReentrantReadWriteLock()): MutableDelegatedField<T, V> =
|
||||
ReadWriteLockMutableDelegatedField(this, readWriteLock)
|
||||
ReadWriteLockMutableDelegatedField(this, readWriteLock)
|
||||
|
||||
|
||||
fun <T, V> ThreadLocal<V?>.delegated(): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField(this)
|
||||
fun <T, V> T.delegated(
|
||||
threadLocal: ThreadLocal<V?>,
|
||||
): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField(threadLocal)
|
||||
|
||||
fun <T, V> T.threadLocalDelegated(): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
|
||||
fun <T, V> T.threadLocalDelegated(type: Class<V>): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
|
||||
fun <T, V : Any> T.threadLocalDelegated(type: KClass<V>): MutableDelegatedField<T, V?> =
|
||||
ThreadLocalMutableDelegatedField()
|
||||
fun <T, V> T.threadLocalDelegated(type: V?): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
|
||||
fun <T, V> T.threadLocalDelegated(type: Class<out V?>): MutableDelegatedField<T, V?> =
|
||||
ThreadLocalMutableDelegatedField()
|
||||
|
||||
fun <T, V> T.threadLocalDelegated(new: () -> V): MutableDelegatedField<T, V> = SimpThreadLocalMutableDelegatedField(new)
|
||||
fun <T, V> T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal<V>, new: () -> V): MutableDelegatedField<T, V> =
|
||||
SimpThreadLocalMutableDelegatedField(simpThreadLocal, new)
|
||||
fun <T, V : Any> T.threadLocalDelegated(type: KClass<V>): MutableDelegatedField<T, V?> =
|
||||
ThreadLocalMutableDelegatedField()
|
||||
|
||||
fun <T, V : Any> SimpThreadLocal<V>.delegated(): MutableDelegatedField<T, V> =
|
||||
SimpThreadLocalMutableDelegatedField(this)
|
||||
|
||||
fun <T, V : Any> T.threadLocalDelegated(
|
||||
threadLocal: ThreadLocal<V?> = ThreadLocal(),
|
||||
new: () -> V,
|
||||
): MutableDelegatedField<T, V> = SimpThreadLocalMutableDelegatedField(SimpThreadLocal(threadLocal, new))
|
||||
//fun <T, V> T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal<V>): MutableDelegatedField<T, V> =
|
||||
// SimpThreadLocalMutableDelegatedField(simpThreadLocal)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.filter(filter: T.(old: V, new: V) -> Boolean): MutableDelegatedField<T, V> =
|
||||
FilterDelegatedField(this, filter)
|
||||
FilterDelegatedField(this, filter)
|
||||
|
||||
fun <T, V> DelegatedField<T, V>.setter(setter: DelegatedField<T, V>.(value: V) -> Unit): DelegatedField<T, V> =
|
||||
SetterDelegatedField(this, setter)
|
||||
SetterDelegatedField(this, setter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.setter(setter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>, value: V) -> Unit): MutableDelegatedField<T, V> =
|
||||
SetterMutableDelegatedField(this, setter)
|
||||
SetterMutableDelegatedField(this, setter)
|
||||
|
||||
fun <T, V> DelegatedField<T, V>.getter(getter: DelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V): DelegatedField<T, V> =
|
||||
GetterDelegatedField(this, getter)
|
||||
GetterDelegatedField(this, getter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.getter(getter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V): MutableDelegatedField<T, V> =
|
||||
GetterMutableDelegatedField(this, getter)
|
||||
GetterMutableDelegatedField(this, getter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
|
||||
ExecutorMutableDelegatedField(this, executor)
|
||||
ExecutorMutableDelegatedField(this, executor)
|
@ -1,6 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
interface DecoratorMutableDelegatedField<in T, V> : DecoratorDelegatedField<T, V> {
|
||||
val mutableDelegatedField: MutableDelegatedField<T, V>
|
||||
override val delegatedField: DelegatedField<T, V> get() = mutableDelegatedField
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
interface DelegatedFieldAttachmentKey<V>
|
@ -1,10 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class GetterMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val getter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = mutableDelegatedField.getter(thisRef, property)
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
class NotNullDelegatedField<in T, out V : Any>(
|
||||
override val delegatedField: DelegatedField<T, V?>,
|
||||
) : DelegatedField<T, V> by delegatedField.cast(), DecoratorDelegatedField<T, V?>
|
@ -1,8 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
class NotNullMutableDelegatedField<in T, V : Any>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V?>,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField.cast(), DecoratorMutableDelegatedField<T, V?>
|
||||
|
@ -1,12 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class SetterMutableDelegatedField<T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
val setter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>, value: V) -> Unit,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
mutableDelegatedField.setter(thisRef, property, value)
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.SimpThreadLocal
|
||||
|
||||
|
||||
class SimpThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: SimpThreadLocal<V>,
|
||||
val new: () -> V
|
||||
) : MutableDelegatedField<T, V> {
|
||||
constructor(new: () -> V) : this(SimpThreadLocal(new = new), new)
|
||||
|
||||
override fun setValue(value: V) = threadLocal.set(value)
|
||||
override fun getValue(): V = threadLocal.get()
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
class ThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: ThreadLocal<V?> = ThreadLocal()
|
||||
) : MutableDelegatedField<T, V?> {
|
||||
override fun setValue(value: V?) = threadLocal.set(value)
|
||||
override fun getValue(): V? = threadLocal.get()
|
||||
}
|
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
@ -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<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
interface ListenableListener<out T, V> : Listener<T, V> {
|
||||
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V>
|
||||
}
|
@ -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<T, V>(
|
||||
override val delegatedField: MutableDelegatedField<T, V>,
|
||||
) : MutableDelegatedField<T, V> by delegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
companion object : DelegatedFieldAttachmentKey<Boolean>
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? {
|
||||
return if (key == Companion) true.uncheckedCast() else super.get(key)
|
||||
}
|
||||
|
||||
private val listenerList = ConcurrentLinkedDeque<T.(old: V, new: V) -> 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<T, V> {
|
||||
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<T, V> {
|
||||
override fun cancel() = listenerList.remove(listener)
|
||||
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener<T, V> {
|
||||
catch = handler
|
||||
return this
|
||||
}
|
||||
|
||||
override fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
||||
finally = handler
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
interface Listener<out T, V> {
|
||||
fun cancel(): Boolean
|
||||
infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Listener<T, V>
|
||||
infix fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V>
|
||||
}
|
@ -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)
|
||||
}
|
@ -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 <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
|
||||
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 <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ListenableMutableDelegatedField(
|
||||
MutableDelegatedFieldValue(initValue)
|
||||
)
|
||||
|
||||
@Listenable
|
||||
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
|
||||
ListenableMutableDelegatedField(this)
|
||||
|
||||
@JvmName("listenable1")
|
||||
@Listenable
|
||||
fun <T, V> listenable(delegatedField: MutableDelegatedField<T, V>): MutableDelegatedField<T, V> =
|
||||
ListenableMutableDelegatedField(delegatedField)
|
||||
|
||||
|
||||
infix operator fun <T, V> ListenableListener<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Listener<T, V> =
|
||||
addListener(listener)
|
||||
|
||||
@OptIn(Listenable::class)
|
||||
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ListenableMutableDelegatedField<Any, V>? {
|
||||
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<KProperty0<V>>().getListenableMutableDelegatedField()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
inline fun <T, V> T.addChangeListener(
|
||||
property: T.() -> KProperty0<V>,
|
||||
): ListenableListener<T, V> {
|
||||
val kProperty0 = property()
|
||||
|
||||
@OptIn(Listenable::class, UncheckedCast::class)
|
||||
val delegatedField = kProperty0
|
||||
.getListenableMutableDelegatedField()
|
||||
.cast<ListenableMutableDelegatedField<T, V>?>()
|
||||
?: throw UnmonitoredFieldException(kProperty0.toString())
|
||||
return object : ListenableListener<T, V> {
|
||||
private val selfList = ConcurrentLinkedQueue<Listener<T, V>>()
|
||||
override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
||||
@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<T, V> {
|
||||
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<T, V> {
|
||||
selfList.forEach {
|
||||
it.finally(handler)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -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<Map<String, Any>>().keys
|
||||
try {
|
||||
Unsafe {
|
||||
Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast<Map<String, Any>>().keys
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -24,7 +24,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives(tasks["kotlinSourcesJar"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
@ -26,7 +30,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
@ -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<String, String>? = 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()
|
||||
}
|
||||
}
|
@ -8,7 +8,8 @@ import io.netty.handler.codec.http.websocketx.*
|
||||
class WebSocketClientChannelHandler(
|
||||
val client: WebSocketClient,
|
||||
val handler: WebSocketHandler,
|
||||
) : SimpleChannelInboundHandler<WebSocketFrame>() {
|
||||
private val autoRelease: Boolean = true,
|
||||
) : SimpleChannelInboundHandler<WebSocketFrame>(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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
33
ts-core/ts-xml/build.gradle.kts
Normal file
33
ts-core/ts-xml/build.gradle.kts
Normal file
@ -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<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml
|
||||
package cn.tursom.core.xml
|
||||
|
||||
import org.dom4j.Document
|
||||
import org.dom4j.Element
|
@ -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 {
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml
|
||||
package cn.tursom.core.xml
|
||||
|
||||
enum class ElementTarget {
|
||||
Attribute, ElementText, SubElement
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface ElementContainerPotableXmlElement : ElementContainerXmlElement, PotableXmlElement {
|
||||
val size: Int
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface ElementContainerXmlElement : XmlElement {
|
||||
val subElement: List<XmlElement>
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface PotableXmlElement : XmlElement {
|
||||
override var name: String
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface TextPotableXmlElement : TextXmlElement, PotableXmlElement {
|
||||
override var text: String
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface TextXmlElement : XmlElement {
|
||||
val text: String
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.utils.xml.interfaces
|
||||
package cn.tursom.core.xml.interfaces
|
||||
|
||||
interface XmlElement {
|
||||
val name: String
|
@ -25,7 +25,7 @@ publishing {
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
37
ts-database/build.gradle.kts
Normal file
37
ts-database/build.gradle.kts
Normal file
@ -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<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["kotlinSourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
82
ts-database/src/main/kotlin/cn/tursom/database/AutoTable.kt
Normal file
82
ts-database/src/main/kotlin/cn/tursom/database/AutoTable.kt
Normal file
@ -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<T : Any>(
|
||||
entityClass: KClass<T>,
|
||||
tableName: String = entityClass.tableName,
|
||||
alias: String? = null,
|
||||
catalog: String? = null,
|
||||
schema: String? = null,
|
||||
val unsafe: Boolean = true,
|
||||
) : BaseTable<T>(tableName, alias, catalog, schema, entityClass) {
|
||||
private val fieldMap: Map<String, KProperty<*>>
|
||||
private val fieldColumns: MutableMap<KProperty<*>, Column<*>> = HashMap()
|
||||
private val fieldNameColumnMap: MutableMap<String, Column<*>> = 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<Property<Any>>())
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
operator fun <R : Any> get(property: KProperty1<T, R?>): Column<R> = fieldColumns[property].uncheckedCast()
|
||||
//operator fun <R : Any> get(property: KProperty1<T, R?>): Column<R> = this[property.simpTableField].cast()
|
||||
|
||||
fun <V : Any> field(): FieldProxy<T, V> = fieldProxyInstance.uncheckedCast()
|
||||
fun <V : Any> field(property: KProperty0<*>): Column<V> = fieldNameColumnMap[property.name].uncheckedCast()
|
||||
|
||||
companion object {
|
||||
private val fieldProxyInstance = FieldProxy<Any, Any>()
|
||||
private val autoTableMap = ConcurrentHashMap<Class<*>, AutoTable<*>>()
|
||||
operator fun <T : Any> get(clazz: KClass<T>): AutoTable<T> = get(clazz.java)
|
||||
|
||||
operator fun <T : Any> get(clazz: Class<T>): AutoTable<T> {
|
||||
var autoTable = autoTableMap[clazz]
|
||||
if (autoTable == null) {
|
||||
synchronized(autoTableMap) {
|
||||
autoTable = AutoTable(clazz.kotlin)
|
||||
autoTableMap[clazz] = autoTable.uncheckedCast()
|
||||
}
|
||||
}
|
||||
return autoTable.uncheckedCast()
|
||||
}
|
||||
|
||||
class FieldProxy<T : Any, V : Any> {
|
||||
operator fun getValue(
|
||||
autoTable: AutoTable<T>,
|
||||
property: KProperty<*>,
|
||||
): Column<V> = autoTable.fieldNameColumnMap[property.name].uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user