mirror of
https://github.com/tursom/TursomServer.git
synced 2024-12-28 05:40:12 +08:00
update
This commit is contained in:
parent
b0cd840376
commit
cc32906fc9
@ -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")
|
||||
|
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
@ -0,0 +1,123 @@
|
||||
package cn.tursom.core
|
||||
|
||||
object TextColor {
|
||||
const val reset = "\u001b[0m"
|
||||
|
||||
enum class DisplayType(val code: Int) {
|
||||
DEFAULT(0), HIGHLIGHT(1), INTENSITY(2), ITALIC(3), UNDERLINE(4),
|
||||
SLOW_BLINK(5), RAPID_BLINK(6), REVERSE(7), INVISIBLE(8), CROSSED_OUT(9),
|
||||
UNDERLINE_OFF(24), BLINK_OFF(25), REVERSE_OFF(27), INVISIBLE_OFF(28), CROSSED_OUT_OFF(29),
|
||||
OVER_LINE(53), OVER_LINE_OFF(55);
|
||||
|
||||
val strCode = "\u001b[${code}m"
|
||||
}
|
||||
|
||||
fun textColor(displayType: DisplayType, textColor: Int, backgroundColor: Int) =
|
||||
"\u001B[${displayType.code};$textColor;${backgroundColor}m"
|
||||
|
||||
fun rgbTextColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||
"\u001B[${displayType.code};38;2;$r;$g;${b}m"
|
||||
|
||||
fun rgbBackgroundColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||
"\u001B[${displayType.code};48;2;$r;$g;${b}m"
|
||||
|
||||
const val black = "\u001b[30m"
|
||||
const val red = "\u001b[31m"
|
||||
const val green = "\u001b[32m"
|
||||
const val yellow = "\u001b[33m"
|
||||
const val blue = "\u001b[34m"
|
||||
const val magenta = "\u001b[35m"
|
||||
const val cyan = "\u001b[36m"
|
||||
const val white = "\u001b[37m"
|
||||
|
||||
const val brightBlack = "\u001b[30;1m"
|
||||
const val brightRed = "\u001b[31;1m"
|
||||
const val brightGreen = "\u001b[32;1m"
|
||||
const val brightYellow = "\u001b[33;1m"
|
||||
const val brightBlue = "\u001b[34;1m"
|
||||
const val brightMagenta = "\u001b[35;1m"
|
||||
const val brightCyan = "\u001b[36;1m"
|
||||
const val brightWhite = "\u001b[37;1m"
|
||||
|
||||
val textColor = Array(256) {
|
||||
"\u001b[38;5;${it}m"
|
||||
}
|
||||
|
||||
fun textColor(color: Int) = textColor[color]
|
||||
fun textColor(color: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||
"\u001B[${displayType.code};38;5;${color}m"
|
||||
|
||||
const val blackBackground = "\u001b[40m"
|
||||
const val redBackground = "\u001b[41m"
|
||||
const val greenBackground = "\u001b[42m"
|
||||
const val yellowBackground = "\u001b[43m"
|
||||
const val blueBackground = "\u001b[44m"
|
||||
const val magentaBackground = "\u001b[45m"
|
||||
const val cyanBackground = "\u001b[46m"
|
||||
const val whiteBackground = "\u001b[47m"
|
||||
|
||||
const val brightBlackBackground = "\u001b[40;1m"
|
||||
const val brightRedBackground = "\u001b[41;1m"
|
||||
const val brightGreenBackground = "\u001b[42;1m"
|
||||
const val brightYellowBackground = "\u001b[43;1m"
|
||||
const val brightBlueBackground = "\u001b[44;1m"
|
||||
const val brightMagentaBackground = "\u001b[45;1m"
|
||||
const val brightCyanBackground = "\u001b[46;1m"
|
||||
const val brightWhiteBackground = "\u001b[47;1m"
|
||||
|
||||
val backgroundColor = Array(256) {
|
||||
"\u001b[48;5;${it}m"
|
||||
}
|
||||
|
||||
const val bold = "\u001b[1m"
|
||||
const val underline = "\u001b[4m"
|
||||
const val reverseColor = "\u001b[7m"
|
||||
|
||||
const val up = "\u001b[1A"
|
||||
const val down = "\u001b[1B"
|
||||
const val left = "\u001b[1C"
|
||||
const val right = "\u001b[1D"
|
||||
|
||||
const val downToNextLine = "\u001b[1E"
|
||||
const val upToPrevLine = "\u001b[1F"
|
||||
|
||||
fun up(step: Int) = "\u001b[${step}A"
|
||||
fun down(step: Int) = "\u001b[${step}B"
|
||||
fun left(step: Int) = "\u001b[${step}C"
|
||||
fun right(step: Int) = "\u001b[${step}D"
|
||||
|
||||
fun downToNextLine(step: Int) = "\u001b[${step}E"
|
||||
fun upToPrevLine(step: Int) = "\u001b[${step}F"
|
||||
|
||||
fun jumpToLine(line: Int) = "\u001b[${line}G"
|
||||
fun jump(line: Int, row: Int) = "\u001b[${line};${row}H"
|
||||
|
||||
const val cleanScreenToEnd = "\u001b[0J"
|
||||
const val cleanScreenFromStart = "\u001b[1J"
|
||||
const val cleanScreen = "\u001b[2J"
|
||||
|
||||
const val cleanLineToEnd = "\u001b[0K"
|
||||
const val cleanLineFromStart = "\u001b[1K"
|
||||
const val cleanLine = "\u001b[2K"
|
||||
|
||||
const val savePosition = "\u001b[s"
|
||||
const val loadPosition = "\u001b[u"
|
||||
|
||||
fun rgbTo8Color(R: Int, G: Int, B: Int): Int {
|
||||
//8色化处理,取RGB的高1位相与。
|
||||
val r1 = R shr 5 and 0x4
|
||||
val g1 = G shr 6 and 0x2
|
||||
val b1 = B shr 7
|
||||
return (r1 or g1 or b1) + 1
|
||||
}
|
||||
|
||||
fun rgbTo16Color(R: Int, G: Int, B: Int): Int {
|
||||
//16色化处理,取R、G的高1位和B的高2位相与
|
||||
val r1 = R shr 4 and 0x8
|
||||
val g1 = G shr 5 and 0x4
|
||||
val b1 = B shr 6 and 0x3
|
||||
return (r1 or g1 or b1) + 1
|
||||
}
|
||||
|
||||
fun rgbTo256Color(r: Int, g: Int, b: Int): Int = ((r / 32 shl 5) + (g / 32 shl 2) + b / 64) and 0xFF
|
||||
}
|
@ -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 {
|
||||
@ -135,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
|
||||
|
||||
@ -251,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) {
|
||||
@ -366,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 {
|
||||
@ -406,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 生成结果,否则范湖自身
|
||||
*/
|
||||
@ -452,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
|
||||
@ -466,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
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ plugins {
|
||||
dependencies {
|
||||
implementation(project(":"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-log"))
|
||||
implementation(project(":ts-core:ts-datastruct"))
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
package cn.tursom.core.clone
|
||||
|
||||
import cn.tursom.core.Unsafe
|
||||
import cn.tursom.core.uncheckedCast
|
||||
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>()")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,110 +1,22 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.core.clone
|
||||
|
||||
import cn.tursom.core.Unsafe
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.*
|
||||
import cn.tursom.core.datastruct.ArrayMap
|
||||
import cn.tursom.core.datastruct.KPropertyValueMap
|
||||
import cn.tursom.core.datastruct.ReadWriteMap
|
||||
import cn.tursom.core.datastruct.SoftArrayMap
|
||||
import cn.tursom.core.final
|
||||
import cn.tursom.log.impl.Slf4jImpl
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.reflect.jvm.javaType
|
||||
|
||||
/**
|
||||
* clone 使用的日志对象
|
||||
*/
|
||||
private val logger = Slf4jImpl.getLogger()
|
||||
|
||||
/**
|
||||
* clone 使用的对象属性类型
|
||||
*/
|
||||
typealias Property<T> = KProperty1<T, Any?>
|
||||
|
||||
val Any.valueMap: Map<String, Any?>
|
||||
get() = if (this is Map<*, *>) {
|
||||
cast()
|
||||
} else {
|
||||
KPropertyValueMap(this)
|
||||
}
|
||||
|
||||
private val injectMapCache = ReadWriteMap<KClass<*>, ArrayMap<String, Property<*>?>>(SoftArrayMap(HashMap()))
|
||||
|
||||
val <T : Any> KClass<T>.injectMap: ArrayMap<String, Property<T>?>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = let {
|
||||
var valueMap = injectMapCache[it] as ArrayMap<String, Property<T>?>?
|
||||
if (valueMap == null) {
|
||||
val properties = it.memberProperties
|
||||
valueMap = ArrayMap(properties.size)
|
||||
(properties as Collection<Property<T>>).forEach { property ->
|
||||
property.isAccessible = true
|
||||
valueMap[property.name] = property
|
||||
}
|
||||
injectMapCache[it] = valueMap as ArrayMap<String, Property<*>?>
|
||||
}
|
||||
valueMap.copy()
|
||||
}
|
||||
|
||||
private val <T : Any> T.injectMap: ArrayMap<String, Property<T>?>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
get() = (this::class as KClass<T>).injectMap
|
||||
|
||||
private val <T> Array<out Pair<Property<*>, Property<T>?>>.injectMap get() = iterator().injectMap
|
||||
private val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
|
||||
get() = let {
|
||||
val valueMap = ArrayMap<String, Property<T>?>()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
forEach { (k, field) ->
|
||||
field?.isAccessible = true
|
||||
valueMap[k.name] = field
|
||||
}
|
||||
//logger.trace("Iterator.injectMap: {}", valueMap)
|
||||
valueMap
|
||||
}
|
||||
|
||||
private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<T>?> = this::class
|
||||
.cast<KClass<T>>()
|
||||
.injectMap
|
||||
.also {
|
||||
if (clazz == null) return@also
|
||||
val clazzThis = this::class.java
|
||||
|
||||
fun import(relation: Relation, property: Property<T>) {
|
||||
if (relation.clazz != clazz) return
|
||||
//logger.trace("relation {} to {}", relation.property, property.name)
|
||||
it[relation.property] = when {
|
||||
relation.skip -> null
|
||||
relation.handler.isEmpty() -> property
|
||||
else -> try {
|
||||
val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java)
|
||||
handler.isAccessible = true
|
||||
object : KMutableProperty1<T, Any?>, KProperty1<T, Any?> by property {
|
||||
override val setter: KMutableProperty1.Setter<T, Any?> get() = TODO()
|
||||
override fun set(receiver: T, value: Any?) =
|
||||
handler(this@injectMap, value).inject(receiver, property)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
//logger.warn("an exception caused on generate inject handler", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parseAnnotation(annotation: Annotation, property: Property<T>) {
|
||||
when (annotation) {
|
||||
is Relation -> import(annotation, property)
|
||||
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
|
||||
}
|
||||
}
|
||||
|
||||
this::class.memberProperties.cast<Collection<KProperty1<T, *>>>().forEach { property ->
|
||||
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
|
||||
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
|
||||
parseAnnotation(annotation, property)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于形式化的将List中的数据映射到实体类上
|
||||
@ -122,7 +34,7 @@ private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<
|
||||
*/
|
||||
inline fun <reified T : Any, S : Any> List<S?>.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||
): List<T> {
|
||||
val list = ArrayList<T>(size)
|
||||
val memberMap = T::class.injectMap
|
||||
@ -131,25 +43,28 @@ inline fun <reified T : Any, S : Any> List<S?>.clone(
|
||||
}
|
||||
forEach {
|
||||
it ?: return@forEach
|
||||
val target = instance<T>(unsafe) ?: return@forEach
|
||||
list.add(it.inject(target, memberMap.iterator()))
|
||||
try {
|
||||
val target = InstantAllocator[T::class.java, unsafe]
|
||||
list.add(it.inject(target, memberMap.iterator()))
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> List<Any?>.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Property<T>?
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Property<T>?,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
fun <T : Any> List<Any?>.clone(
|
||||
target: T,
|
||||
vararg relation: Property<T>?
|
||||
vararg relation: Property<T>?,
|
||||
): T = clone(target, relation.iterator())
|
||||
|
||||
fun <T : Any> List<Any?>.clone(
|
||||
target: T,
|
||||
relation: Iterator<Property<T>?>
|
||||
relation: Iterator<Property<T>?>,
|
||||
): T = relation.mapIndexed { index, kProperty1 ->
|
||||
(kProperty1 ?: return@mapIndexed null).name to this[index]
|
||||
}.clone(target)
|
||||
@ -157,29 +72,30 @@ fun <T : Any> List<Any?>.clone(
|
||||
|
||||
/**
|
||||
* 新建并拷贝
|
||||
* @author 王景阔
|
||||
* 创建类型 T 的实例
|
||||
* 并将对象两个的所有同名字段拷贝进新建的实例中
|
||||
* @return 新建的实例
|
||||
* @param unsafe 是否允许使用 Unsafe 创建对象,unsafe 不需调用构造函数,可以在没有默认构造函数的情况下生成对象
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(instance<T>(unsafe)!!)
|
||||
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(InstantAllocator[T::class.java, unsafe])
|
||||
|
||||
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(instance(unsafe, clazz)!!)
|
||||
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(InstantAllocator[clazz, unsafe])
|
||||
|
||||
@JvmName("unsafeClone")
|
||||
inline fun <reified T : Any> Any.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Pair<String, Property<T>?>,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
inline fun <reified T : Any, S : Any> S.clone(
|
||||
unsafe: Boolean = true,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
||||
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||
|
||||
fun Any.cloneMap(): Map<in String, Any?> = when (this) {
|
||||
is Map<*, *> -> @Suppress("UNCHECKED_CAST") (this as Map<Any?, Any?>).mapKeys { it.key.toString() }
|
||||
is Map<*, *> -> uncheckedCast<Map<Any?, Any?>>().mapKeys { it.key.toString() }
|
||||
is Iterator<*> -> {
|
||||
val valueMap = HashMap<String, Any?>()
|
||||
(this as Iterator<Any?>).forEach {
|
||||
@ -201,22 +117,22 @@ fun <T : Any> Any.clone(target: T): T = apply { injectWithoutProperty(target) }.
|
||||
|
||||
fun <T : Any, S : Any> S.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<S>, Property<T>?>>
|
||||
iterator: Iterator<Pair<Property<S>, Property<T>?>>,
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
||||
valueMap
|
||||
//.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
|
||||
.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
|
||||
.clone(target, iterator.injectMap.iterator(), this::class)
|
||||
}
|
||||
|
||||
fun <T : Any> Any.clone(
|
||||
target: T,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
vararg relation: Pair<String, Property<T>?>,
|
||||
): T = clone(target, relation.iterator())
|
||||
|
||||
@JvmName("unsafeClone")
|
||||
fun <T : Any> Any.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>
|
||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
||||
valueMap.clone(target, iterator, this::class)
|
||||
}
|
||||
@ -225,9 +141,9 @@ fun <T : Any> Any.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||
clazz: KClass<*>? = null
|
||||
clazz: KClass<*>? = null,
|
||||
): T {
|
||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
||||
val memberMap = target.injectMap(clazz)
|
||||
iterator.forEach { (k, v) ->
|
||||
memberMap[k] = v
|
||||
}
|
||||
@ -238,9 +154,9 @@ fun <T : Any> Map<in String, Any?>.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
||||
clazz: KClass<*>? = null
|
||||
clazz: KClass<*>? = null,
|
||||
): T {
|
||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
||||
val memberMap = target.injectMap(clazz)
|
||||
iterator.forEach { (k, v) ->
|
||||
memberMap[k.get(target)?.toString() ?: return@forEach] = v
|
||||
}
|
||||
@ -251,13 +167,13 @@ fun <T : Any> Map<in String, Any?>.clone(
|
||||
fun <T : Any> Map<in String, Any?>.clone(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
||||
clazz: KClass<*>? = null
|
||||
clazz: KClass<*>? = null,
|
||||
): T {
|
||||
val memberMap = target.injectMap(clazz)
|
||||
iterator.forEach { (k, v) ->
|
||||
memberMap[k ?: return@forEach] = v
|
||||
}
|
||||
//logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
|
||||
logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
|
||||
return inject(target, memberMap.iterator())
|
||||
}
|
||||
|
||||
@ -268,229 +184,6 @@ fun <T : Any> Any.checkPropertyClone(target: T, ifClone: () -> T): T =
|
||||
target
|
||||
}
|
||||
|
||||
//fun <T> Any.checkPropertyClone(targetClass: KClass<out Any>, ifClone: () -> T): T {
|
||||
// if (targetClass.findAnnotation<NoPropertyClone>()?.classList?.contains(this::class) != true)
|
||||
// ifClone()
|
||||
//}
|
||||
|
||||
fun <T : Any> Any.injectWithoutProperty(target: T): T {
|
||||
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
|
||||
if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try {
|
||||
val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java)
|
||||
handler.isAccessible = true
|
||||
handler(target, this)?.inject(target, property)
|
||||
} catch (e: Exception) {
|
||||
//logger.warn("an exception caused on global inject", e)
|
||||
}
|
||||
}
|
||||
|
||||
target::class.memberProperties
|
||||
.cast<Collection<KProperty1<Any, *>>>()
|
||||
.forEach { property ->
|
||||
property.annotations.forEach { annotation ->
|
||||
when (annotation) {
|
||||
is Relation -> parseAnnotation(annotation, property)
|
||||
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
||||
}
|
||||
}
|
||||
property.javaField?.annotations?.forEach { annotation ->
|
||||
when (annotation) {
|
||||
is Relation -> parseAnnotation(annotation, property)
|
||||
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String?, Property<T>?>>
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
@JvmName("injectMap")
|
||||
fun <T : Any> Any.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>
|
||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||
|
||||
fun <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<String, Property<T>?>>
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Map<in String, Any?>.p2pInject(
|
||||
target: T,
|
||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
@JvmName("injectMap")
|
||||
fun <T : Any> Map<in String, Any?>.inject(
|
||||
target: T,
|
||||
iterator: Iterator<Map.Entry<String, Property<T>?>>
|
||||
): T {
|
||||
iterator.forEach { (k, t) ->
|
||||
val value = this[k] ?: return@forEach
|
||||
value.inject(target, t ?: return@forEach)
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
fun <T : Any> Any.inject(target: T, property: Property<T>) {
|
||||
//logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
|
||||
when (property) {
|
||||
is KMutableProperty1<*, *> -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
property as KMutableProperty1<T, Any?>
|
||||
property.isAccessible = true
|
||||
try {
|
||||
property.set(target, cast(this, property.returnType.javaType.cast()) ?: return)
|
||||
} catch (e: ClassCastException) {
|
||||
//logger.trace("inject failed", e)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val field = property.javaField ?: return
|
||||
field.isAccessible = true
|
||||
field.final = false
|
||||
try {
|
||||
field.set(target, cast(this, field.type) ?: return)
|
||||
} catch (e: Exception) {
|
||||
//logger.trace("inject failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) {
|
||||
source
|
||||
} else when (target) {
|
||||
Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
||||
Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar()
|
||||
Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
||||
Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
||||
Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
||||
Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
||||
Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
||||
Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
||||
|
||||
java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
||||
java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()
|
||||
?.toChar()
|
||||
java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
||||
java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
||||
java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
||||
java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
||||
java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
||||
java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
||||
|
||||
String::class.java -> source.toString()
|
||||
|
||||
else -> source
|
||||
}
|
||||
|
||||
fun <T : Any> T.read(source: Any?): T = source?.clone(this) ?: this
|
||||
|
||||
fun <T : Any, S : Any> T.read(
|
||||
source: S?,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): T = source?.clone(this, relation.iterator()) ?: this
|
||||
|
||||
fun <T : Any> T.read(
|
||||
source: Map<in String, Any?>?,
|
||||
vararg relation: Pair<String, Property<T>?>
|
||||
): T = source?.clone(this, relation.iterator()) ?: this
|
||||
|
||||
|
||||
fun <T : Any> T.p2pRead(
|
||||
source: Map<in String, Any?>?,
|
||||
vararg relation: Pair<Property<T>, Property<T>?>
|
||||
): T {
|
||||
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
|
||||
return source?.p2pInject(this, relation.iterator()) ?: this
|
||||
}
|
||||
|
||||
fun <T : Any> T.p2pRead(
|
||||
source: Map<in String, Any?>?
|
||||
): T {
|
||||
source ?: return this
|
||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
||||
val relation = properties.mapNotNull { property ->
|
||||
val key = property.javaField?.getAnnotation(Key::class.java)?.key ?: return@mapNotNull null
|
||||
val keyProperty = properties.find { it.name == key } ?: return@mapNotNull null
|
||||
keyProperty to property
|
||||
}
|
||||
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
|
||||
return source.p2pInject(this, relation.iterator())
|
||||
}
|
||||
|
||||
fun <T : Any> T.p2pRead(
|
||||
source: Any?
|
||||
): T {
|
||||
source ?: return this
|
||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
||||
properties.forEach { property ->
|
||||
val keyAnnotation = property.javaField?.getAnnotation(Key::class.java) ?: return@forEach
|
||||
if (keyAnnotation.handler.isEmpty()) return@forEach
|
||||
if (keyAnnotation.clazz.isInstance(source).not()) return@forEach
|
||||
val handler = this::class.java.getDeclaredMethod(keyAnnotation.handler, keyAnnotation.clazz.java)
|
||||
(handler(this, source) ?: return@forEach).inject(this, property)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : Any, S : Any> List<T>.read(
|
||||
source: List<S>,
|
||||
vararg relation: Pair<Property<S>, Property<T>?>
|
||||
): List<T> {
|
||||
val memberMap = this[0].injectMap as MutableMap<String, Property<T>?>
|
||||
relation.forEach { (k, v) ->
|
||||
memberMap[k.name] = v
|
||||
}
|
||||
return source.mapIndexed { index, it -> it.inject(this[index], memberMap.iterator()) }
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> read(vararg values: Any, unsafe: Boolean = true): T {
|
||||
val instance = instance<T>(unsafe)!!
|
||||
values.forEach {
|
||||
it.clone(instance)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> read(value: Any, unsafe: Boolean = true): T = value.clone(unsafe)
|
||||
|
||||
fun <T : Any> T.readWithoutProperty(vararg values: Any): T {
|
||||
values.forEach {
|
||||
it.injectWithoutProperty(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
|
||||
|
||||
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T? = try {
|
||||
clazz.newInstance()!!
|
||||
} catch (e: Exception) {
|
||||
if (unsafe) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Unsafe.unsafe.allocateInstance(clazz) as T?
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) -> Pair<K, V>?): Map<K, V> {
|
||||
val map = ArrayMap<K, V>()
|
||||
@ -502,6 +195,113 @@ inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) ->
|
||||
return map
|
||||
}
|
||||
|
||||
fun <T : Any> T.mapRead(map: Map<in String, Any?>, key: KProperty1<T, *>): T {
|
||||
return read(map[key.get(this)?.toString() ?: return this] ?: return this)
|
||||
fun <T : Any, F : Any?> T.set(field: KProperty1<T, F>, value: F): T {
|
||||
(value as Any?)?.inject(this, field as Property<T>)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : Any> T.deepClone(): T = when (this) {
|
||||
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
|
||||
is CharArray -> copyOf().uncheckedCast()
|
||||
is BooleanArray -> copyOf().uncheckedCast()
|
||||
is ByteArray -> copyOf().uncheckedCast()
|
||||
is ShortArray -> copyOf().uncheckedCast()
|
||||
is IntArray -> copyOf().uncheckedCast()
|
||||
is LongArray -> copyOf().uncheckedCast()
|
||||
is FloatArray -> copyOf().uncheckedCast()
|
||||
is DoubleArray -> copyOf().uncheckedCast()
|
||||
else -> deepClone(HashMap())
|
||||
}
|
||||
|
||||
private fun <T : Any> T.deepClone(clonedMap: MutableMap<Any, Any>): T =
|
||||
clonedMap[this]?.uncheckedCast<T>() ?: when (this) {
|
||||
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
|
||||
is CharArray -> copyOf().uncheckedCast()
|
||||
is BooleanArray -> copyOf().uncheckedCast()
|
||||
is ByteArray -> copyOf().uncheckedCast()
|
||||
is ShortArray -> copyOf().uncheckedCast()
|
||||
is IntArray -> copyOf().uncheckedCast()
|
||||
is LongArray -> copyOf().uncheckedCast()
|
||||
is FloatArray -> copyOf().uncheckedCast()
|
||||
is DoubleArray -> copyOf().uncheckedCast()
|
||||
is Array<*> -> {
|
||||
val instance = java.lang.reflect.Array.newInstance(javaClass.componentType, size).uncheckedCast<Array<Any?>>()
|
||||
forEachIndexed { index, it ->
|
||||
instance[index] = it?.deepClone(clonedMap)
|
||||
}
|
||||
instance.uncheckedCast()
|
||||
}
|
||||
else -> {
|
||||
val clazz = javaClass
|
||||
val newInstance = unsafeInstance(clazz)!!
|
||||
clonedMap[this] = newInstance
|
||||
clazz.forAllFields { field ->
|
||||
if (field.isStatic()) return@forAllFields
|
||||
field.isAccessible = true
|
||||
field.set(newInstance, field.get(this)?.deepClone(clonedMap))
|
||||
}
|
||||
newInstance
|
||||
}
|
||||
}
|
||||
|
||||
fun Any?.details(name: String = "", skipStatic: Boolean = true) = buildString {
|
||||
this@details.details(HashMap(), this, "", name, skipStatic)
|
||||
}
|
||||
|
||||
private fun Any?.details(
|
||||
map: MutableMap<Any, Int>,
|
||||
builder: StringBuilder,
|
||||
indentation: String,
|
||||
name: String = "",
|
||||
skipStatic: Boolean = true,
|
||||
directValue: String = "|- ",
|
||||
objectValue: String = "/- ",
|
||||
hint: String = "${TextColor.red}|${TextColor.reset} ",
|
||||
tmpIndentation: String = "",
|
||||
type: String? = null,
|
||||
) {
|
||||
when (this) {
|
||||
null, is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*>, is String ->
|
||||
builder.append("$indentation$tmpIndentation$directValue$name(${type ?: this?.javaClass?.name ?: "null"}): $this\n")
|
||||
is CharArray -> builder.append("$indentation$tmpIndentation$directValue$name(CharArray): ${String(this)}\n")
|
||||
is BooleanArray -> builder.append("$indentation$tmpIndentation$directValue$name(BooleanArray): ${asList()}\n")
|
||||
is ByteArray -> builder.append("$indentation$tmpIndentation$directValue$name(ByteArray): 0x${toHexString()}\n")
|
||||
is ShortArray -> builder.append("$indentation$tmpIndentation$directValue$name(ShortArray): ${asList()}\n")
|
||||
is IntArray -> builder.append("$indentation$tmpIndentation$directValue$name(IntArray): ${asList()}\n")
|
||||
is LongArray -> builder.append("$indentation$tmpIndentation$directValue$name(LongArray): ${asList()}\n")
|
||||
is FloatArray -> builder.append("$indentation$tmpIndentation$directValue$name(FloatArray): ${asList()}\n")
|
||||
is DoubleArray -> builder.append("$indentation$tmpIndentation$directValue$name(DoubleArray): ${asList()}\n")
|
||||
is Array<*> -> {
|
||||
builder.append("$indentation$tmpIndentation$objectValue$name: (Array<${javaClass.componentType.name}>, ${hashCode()})\n")
|
||||
if (this !in map) {
|
||||
map[this] = hashCode()
|
||||
val newIndentation = "$indentation$hint"
|
||||
forEachIndexed { index, it ->
|
||||
val newTmpIndentation = "|- ${name.ifEmpty { "array" }}[$index]"
|
||||
it.details(
|
||||
map, builder, newIndentation,
|
||||
skipStatic = skipStatic,
|
||||
directValue = " = ",
|
||||
objectValue = " = /- ",
|
||||
hint = "${TextColor.red}|${TextColor.reset} ${" ".repeat(newTmpIndentation.length + 1)}${TextColor.red}|${TextColor.reset} ",
|
||||
tmpIndentation = newTmpIndentation
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
in map -> builder.append("$indentation$tmpIndentation$directValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${map[this]}, generated)\n")
|
||||
else -> {
|
||||
map[this] = this.hashCode()
|
||||
builder.append("$indentation$tmpIndentation$objectValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${hashCode()})\n")
|
||||
val newIndentation = "$indentation$hint"
|
||||
javaClass.forAllFields { field ->
|
||||
if (skipStatic && field.isStatic()) {
|
||||
return@forAllFields
|
||||
}
|
||||
field.isAccessible = true
|
||||
val value = field.get(this)
|
||||
value.details(map, builder, newIndentation, field.name, skipStatic, type = field.type.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,270 @@
|
||||
package cn.tursom.core.clone
|
||||
|
||||
import cn.tursom.core.Unsafe
|
||||
import cn.tursom.core.allMemberProperties
|
||||
import cn.tursom.core.datastruct.KPropertyValueMap
|
||||
import cn.tursom.core.datastruct.SoftArrayMap
|
||||
import cn.tursom.core.unaryPlus
|
||||
import cn.tursom.core.uncheckedCast
|
||||
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
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@ -149,7 +149,7 @@ open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
override fun setValue(newValue: V): V = value.also { value = newValue }
|
||||
override fun compareTo(other: K): Int {
|
||||
return if (key is Comparable<*>) {
|
||||
key.cast<Comparable<K>>().compareTo(other)
|
||||
key.uncheckedCast<Comparable<K>>().compareTo(other)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
class DefaultValueMap<K, V>(
|
||||
private val map: Map<K, V?>,
|
||||
private val defaultValue: (K) -> V
|
||||
) : Map<K, V> by map.cast() {
|
||||
private val defaultValue: (K) -> V,
|
||||
) : Map<K, V> by map.uncheckedCast() {
|
||||
override val entries: Set<Map.Entry<K, V>> get() = Entry()
|
||||
override val values: Collection<V> get() = Values()
|
||||
|
||||
@ -21,8 +21,8 @@ class DefaultValueMap<K, V>(
|
||||
}
|
||||
|
||||
inner class Entry(
|
||||
private val entries: Set<Map.Entry<K, V?>> = map.entries
|
||||
) : Set<Map.Entry<K, V>> by entries.cast() {
|
||||
private val entries: Set<Map.Entry<K, V?>> = map.entries,
|
||||
) : Set<Map.Entry<K, V>> by entries.uncheckedCast() {
|
||||
override val size: Int get() = entries.count { it.value != null }
|
||||
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
||||
override fun iterator(): Iterator<Map.Entry<K, V>> = EntryIterator()
|
||||
@ -32,7 +32,7 @@ class DefaultValueMap<K, V>(
|
||||
private var next: Map.Entry<K, V>? = null
|
||||
override fun hasNext(): Boolean {
|
||||
while (iterator.hasNext()) {
|
||||
next = iterator.next().cast()
|
||||
next = iterator.next().uncheckedCast()
|
||||
if (next?.value != null) {
|
||||
return true
|
||||
}
|
||||
@ -44,13 +44,13 @@ class DefaultValueMap<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
inner class Values(
|
||||
private val values: Collection<V?> = map.values
|
||||
) : Collection<V> by values.cast() {
|
||||
private val values: Collection<V?> = map.values,
|
||||
) : Collection<V> by values.uncheckedCast() {
|
||||
override val size: Int get() = values.count { it != null }
|
||||
override fun isEmpty(): Boolean = values.first { it != null } == null
|
||||
override fun iterator(): Iterator<V> = ValuesIterator()
|
||||
@ -61,7 +61,7 @@ class DefaultValueMap<K, V>(
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
while (iterator.hasNext()) {
|
||||
next = iterator.next().cast()
|
||||
next = iterator.next().uncheckedCast()
|
||||
if (next != null) {
|
||||
return true
|
||||
}
|
||||
@ -73,7 +73,7 @@ class DefaultValueMap<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
class DefaultValueMutableMap<K, V>(
|
||||
private val map: MutableMap<K, V?>,
|
||||
private val defaultValue: (K) -> V
|
||||
) : MutableMap<K, V> by map.cast() {
|
||||
private val defaultValue: (K) -> V,
|
||||
) : MutableMap<K, V> by map.uncheckedCast() {
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = Entry()
|
||||
override val values: MutableCollection<V> get() = Values()
|
||||
|
||||
@ -19,19 +19,19 @@ class DefaultValueMutableMap<K, V>(
|
||||
}
|
||||
|
||||
inner class Entry(
|
||||
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries
|
||||
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.cast() {
|
||||
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries,
|
||||
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.uncheckedCast() {
|
||||
override val size: Int get() = entries.count { it.value != null }
|
||||
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = EntryIterator()
|
||||
|
||||
inner class EntryIterator(
|
||||
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator()
|
||||
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.cast() {
|
||||
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator(),
|
||||
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.uncheckedCast() {
|
||||
private var next: Map.Entry<K, V>? = null
|
||||
override fun hasNext(): Boolean {
|
||||
while (iterator.hasNext()) {
|
||||
next = iterator.next().cast()
|
||||
next = iterator.next().uncheckedCast()
|
||||
if (next?.value != null) {
|
||||
return true
|
||||
}
|
||||
@ -43,25 +43,25 @@ class DefaultValueMutableMap<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
inner class Values(
|
||||
private val values: MutableCollection<V?> = map.values
|
||||
) : MutableCollection<V> by values.cast() {
|
||||
private val values: MutableCollection<V?> = map.values,
|
||||
) : MutableCollection<V> by values.uncheckedCast() {
|
||||
override val size: Int get() = values.count { it != null }
|
||||
override fun isEmpty(): Boolean = values.first { it != null } == null
|
||||
override fun iterator(): MutableIterator<V> = ValuesIterator()
|
||||
|
||||
inner class ValuesIterator(
|
||||
private val iterator: MutableIterator<V?> = values.iterator()
|
||||
) : MutableIterator<V> by iterator.cast() {
|
||||
private val iterator: MutableIterator<V?> = values.iterator(),
|
||||
) : MutableIterator<V> by iterator.uncheckedCast() {
|
||||
private var next: V? = null
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
while (iterator.hasNext()) {
|
||||
next = iterator.next().cast()
|
||||
next = iterator.next().uncheckedCast()
|
||||
if (next != null) {
|
||||
return true
|
||||
}
|
||||
@ -73,7 +73,7 @@ class DefaultValueMutableMap<K, V>(
|
||||
next != null -> next
|
||||
hasNext() -> next
|
||||
else -> throw NoSuchElementException()
|
||||
}.cast()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.memberProperties
|
||||
@ -23,7 +23,7 @@ class KPropertyValueMap(val target: Any) : Map<String, Any?> {
|
||||
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
||||
var map = propertiesMapCache[clazz]
|
||||
if (map == null) {
|
||||
map = clazz.memberProperties.cast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
||||
properties.forEach {
|
||||
it.isAccessible = true
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@ -17,8 +17,8 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
|
||||
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
|
||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().uncheckedCast()
|
||||
override val values: MutableCollection<V> get() = arrValue.asList().uncheckedCast<MutableList<V>>().subList(0, end)
|
||||
|
||||
/**
|
||||
* @param key 查找的键
|
||||
@ -59,7 +59,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
fun setByIndex(index: Int, value: V): V? {
|
||||
val oldValue = arrValue[end]
|
||||
arrValue[index] = value
|
||||
return oldValue.cast()
|
||||
return oldValue.uncheckedCast()
|
||||
}
|
||||
|
||||
override fun delete(key: K): V? {
|
||||
@ -72,7 +72,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
||||
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
|
||||
end--
|
||||
return oldValue.cast()
|
||||
return oldValue.uncheckedCast()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
@ -83,7 +83,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (end <= 0) {
|
||||
null
|
||||
} else {
|
||||
arrValue[0].cast()
|
||||
arrValue[0].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arr[index].cast()
|
||||
arr[index].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arrValue[index].cast()
|
||||
arrValue[index].uncheckedCast()
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,10 +194,10 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
val map: ParallelArrayMap<K, V>,
|
||||
val index: Int
|
||||
) : MutableMap.MutableEntry<K, V> {
|
||||
override val key: K get() = map.getKeyByIndex(index).cast()
|
||||
override val value: V get() = map.getByIndex(index).cast()
|
||||
override val key: K get() = map.getKeyByIndex(index).uncheckedCast()
|
||||
override val value: V get() = map.getByIndex(index).uncheckedCast()
|
||||
override fun setValue(newValue: V): V {
|
||||
return map.setByIndex(index, newValue).cast()
|
||||
return map.setByIndex(index, newValue).uncheckedCast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
package cn.tursom.core.delegation
|
||||
|
||||
import cn.tursom.core.*
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import cn.tursom.core.SimpThreadLocal
|
||||
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
|
||||
@ -126,99 +128,3 @@ fun <T, V> MutableDelegatedField<T, V>.getter(getter: MutableDelegatedField<T, V
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
|
||||
ExecutorMutableDelegatedField(this, executor)
|
||||
|
||||
@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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
@ -0,0 +1,32 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-delegation"))
|
||||
}
|
||||
|
||||
@kotlin.Suppress("UNCHECKED_CAST")
|
||||
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||
|
||||
tasks.register("install") {
|
||||
finalizedBy(tasks["publishToMavenLocal"])
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
|
||||
from(components["java"])
|
||||
try {
|
||||
artifact(tasks["sourcesJar"])
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.core.delegation
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
/**
|
||||
* 标识一个属性可以被指定的 FieldChangeListener 监听
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.core.delegation
|
||||
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>
|
@ -1,5 +1,8 @@
|
||||
package cn.tursom.core.delegation
|
||||
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
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.core.delegation
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
interface Listener<out T, V> {
|
||||
fun cancel(): Boolean
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.core.delegation
|
||||
package cn.tursom.core.delegation.observer
|
||||
|
||||
class UnmonitoredFieldException : Exception {
|
||||
constructor() : super()
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.core.encrypt
|
||||
|
||||
import cn.tursom.core.Unsafe
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
@ -72,7 +72,7 @@ class ECC(
|
||||
val standardCurveLineSet by lazy {
|
||||
try {
|
||||
Unsafe {
|
||||
Class.forName("sun.security.ec.CurveDB")["nameMap"].cast<Map<String, Any>>().keys
|
||||
Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast<Map<String, Any>>().keys
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
emptySet()
|
||||
|
@ -5,9 +5,9 @@ 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")
|
||||
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")
|
||||
|
Loading…
Reference in New Issue
Block a user