kotlinx.reflect.lite.impl.CacheByClass.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx.reflect.lite Show documentation
Show all versions of kotlinx.reflect.lite Show documentation
Experimental lightweight library that replaces existing 'kotlin-reflect' implementation
The newest version!
package kotlinx.reflect.lite.jvm.internal
import java.util.concurrent.*
// https://github.com/JetBrains/kotlin/blob/14b13a2f17cb8a4a4fcdc9d781d87f2c8666f61d/core/reflection.jvm/src/kotlin/reflect/jvm/internal/CacheByClass.kt
/*
* By default, we use ClassValue-based caches in reflection to avoid classloader leaks,
* but ClassValue is not available on Android, thus we attempt to check it dynamically
* and fallback to ConcurrentHashMap-based cache.
*
* NB: if you are changing the name of the outer file (CacheByClass.kt), please also change the corresponding
* proguard rules
*/
private val useClassValue = runCatching {
Class.forName("java.lang.ClassValue")
}.map { true }.getOrDefault(false)
internal abstract class CacheByClass {
abstract fun get(key: Class<*>): V
abstract fun clear()
}
/**
* Creates a **strongly referenced** cache of values associated with [Class].
* Values are computed using provided [compute] function.
*
* `null` values are not supported, though there aren't any technical limitations.
*/
internal fun createCache(compute: (Class<*>) -> V): CacheByClass {
return if (useClassValue) ClassValueCache(compute) else ConcurrentHashMapCache(compute)
}
private class ClassValueCache(private val compute: (Class<*>) -> V) : CacheByClass() {
@Volatile
private var classValue = initClassValue()
private fun initClassValue() = object : ClassValue() {
override fun computeValue(type: Class<*>): V {
return compute(type)
}
}
override fun get(key: Class<*>): V = classValue[key]
override fun clear() {
/*
* ClassValue does not have a proper `clear()` method but is properly weak-referenced,
* thus abandoning ClassValue instance will eventually clear all associated values.
*/
classValue = initClassValue()
}
}
/**
* We no longer support Java 6, so the only place we use this cache is Android, where there
* are no classloader leaks issue, thus we can safely use strong references and do not bother
* with WeakReference wrapping.
*/
private class ConcurrentHashMapCache(private val compute: (Class<*>) -> V) : CacheByClass() {
private val cache = ConcurrentHashMap, V>()
override fun get(key: Class<*>): V = cache.getOrPut(key) { compute(key) }
override fun clear() {
cache.clear()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy