Merge remote-tracking branch 'origin/master' into master

This commit is contained in:
tursom 2021-06-15 00:01:53 +08:00
commit eeacd926b2
193 changed files with 8359 additions and 812 deletions

View File

@ -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) {
}
}

View File

@ -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")

View File

@ -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) {
}
}

View 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>()")
}
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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()
private fun update(): T {
val value = new()
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)
return value
value
} else {
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()
}
}

View 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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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) {
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -7,5 +7,5 @@ import kotlin.reflect.KClass
annotation class Key(
val key: String = "",
val clazz: KClass<*> = Any::class,
val handler: String = ""
val handler: String = "",
)

View File

@ -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<*>,
)

View File

@ -9,7 +9,7 @@ annotation class Relation(
val property: String = "",
val skip: Boolean = false,
val handler: String = "",
val handleClass: KClass<*> = Any::class
val handleClass: KClass<*> = Any::class,
)

View File

@ -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,
)

View File

@ -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
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)
}
}
}
}

View File

@ -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
}

View File

@ -24,7 +24,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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) {
}
}

View File

@ -26,7 +26,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package cn.tursom.utils
package cn.tursom.core.datastruct
interface AsyncIterator<T> {
/**

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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

View File

@ -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()
}
}
}

View File

@ -23,7 +23,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
interface DecoratorDelegatedField<in T, out V> {
val delegatedField: DelegatedField<T, V>

View File

@ -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
}

View File

@ -0,0 +1,5 @@
package cn.tursom.core.delegation
interface DecoratorMutableDelegatedField<in T, V> : DecoratorDelegatedField<T, V> {
override val delegatedField: MutableDelegatedField<T, V>
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KProperty

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KProperty

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KProperty

View File

@ -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)
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KProperty0

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KMutableProperty0

View File

@ -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)
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
import kotlin.reflect.KProperty

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.delegation
package cn.tursom.core.delegation
class SetterDelegatedField<T, V>(
override val delegatedField: DelegatedField<T, V>,

View File

@ -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)
}
}

View File

@ -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>>>()
}
}

View File

@ -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>>>()
}
}

View File

@ -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
@ -29,12 +29,23 @@ fun getDelegate(obj: Any?, field: String): DelegatedField<*, *>? {
val <V> KProperty0<V>.getOwnerDelegated: DelegatedField<*, V>?
get() = getDelegate(receiver, name).castOrNull()
/**
* 获取委托过后的值
* 不会触发getter方法
*/
val <V> KProperty0<V>.getDelegatedValue: V?
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
@ -52,10 +63,19 @@ val <V> KProperty0<V>.delegated: DelegatedField<Any, V> get() = KPropertyDelegat
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> =
@ -67,14 +87,29 @@ val <T, V> MutableDelegatedField<T, V>.readWriteLocked: MutableDelegatedField<T,
fun <T, V> MutableDelegatedField<T, V>.readWriteLocked(readWriteLock: ReadWriteLock = ReentrantReadWriteLock()): MutableDelegatedField<T, V> =
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> T.threadLocalDelegated(type: V?): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
fun <T, V> T.threadLocalDelegated(type: Class<out V?>): MutableDelegatedField<T, V?> =
ThreadLocalMutableDelegatedField()
fun <T, V : Any> T.threadLocalDelegated(type: KClass<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> 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)

View File

@ -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
}

View File

@ -1,3 +0,0 @@
package cn.tursom.delegation
interface DelegatedFieldAttachmentKey<V>

View File

@ -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)
}

View File

@ -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?>

View File

@ -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?>

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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()
}

View 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) {
}
}
}
}

View File

@ -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

View File

@ -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>
}

View File

@ -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
}
}
}
}

View File

@ -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>
}

View File

@ -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)
}

View File

@ -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
}
}
}

View File

@ -26,7 +26,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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 {
try {
Unsafe {
CurveDB::class.java["nameMap"].cast<Map<String, Any>>().keys
Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast<Map<String, Any>>().keys
}
} catch (e: Exception) {
emptySet()
}
}
}

View File

@ -24,7 +24,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -26,7 +26,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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) {
}
}

View File

@ -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

View File

@ -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)

View File

@ -24,7 +24,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -25,7 +25,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View File

@ -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) {
}
}

View File

@ -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()
}
}

View File

@ -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(
val handshakerAdapter = WebSocketClientHandshakerAdapter(
WebSocketClientHandshakerFactory.newHandshaker(
handshakerUri ?: uri, WebSocketVersion.V13, null, true, httpHeaders
), this, handler)
val handler = WebSocketClientChannelHandler(this, handler)
), 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()
}
}

View File

@ -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()
}
}
}

View File

@ -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 {

View 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) {
}
}
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml
package cn.tursom.core.xml
import org.dom4j.Document
import org.dom4j.Element

View File

@ -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 {

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml
package cn.tursom.core.xml
enum class ElementTarget {
Attribute, ElementText, SubElement

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface ElementContainerPotableXmlElement : ElementContainerXmlElement, PotableXmlElement {
val size: Int

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface ElementContainerXmlElement : XmlElement {
val subElement: List<XmlElement>

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface PotableXmlElement : XmlElement {
override var name: String

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface TextPotableXmlElement : TextXmlElement, PotableXmlElement {
override var text: String

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface TextXmlElement : XmlElement {
val text: String

View File

@ -1,4 +1,4 @@
package cn.tursom.utils.xml.interfaces
package cn.tursom.core.xml.interfaces
interface XmlElement {
val name: String

View File

@ -25,7 +25,7 @@ publishing {
from(components["java"])
try {
artifact(tasks["sourcesJar"])
artifact(tasks["kotlinSourcesJar"])
} catch (e: Exception) {
}
}

View 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) {
}
}
}
}

View 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