Kotlin delegate property by lazy that is thread local - properties

Is there a simple way get a delegated property by lazy's value computed per thread like ThreadLocal?
LazyThreadSafetyMode controls concurrent initialization, with .NONE coming close to the desired functionality by allowing multiple threads to receive different values, but has subsequent post initialization calls referencing the same object, returning the same singular value regardless of thread, with some cases returning null.
Regardless of concurrent initialization, or late initialization, the property would cache a unique value per thread.

The Kotlin delegates are easy to extend with your own implementation.
You can make your delegate maintain a ThreadLocal<T> with initialValue calculated by the function that is passed:
class ThreadLocalLazy<T>(val provider: () -> T) :ReadOnlyProperty<Any?, T> {
private val threadLocal = object : ThreadLocal<T>() {
override fun initialValue(): T = provider()
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T =
threadLocal.get()
}
Or maintain a Lazy<T> per thread with ThreadLocal<Lazy<T>>, so that your delegate can implement Lazy<T> by itself:
class ThreadLocalLazy<T>(val provider: () -> T) : Lazy<T> {
private val threadLocal = object : ThreadLocal<Lazy<T>>() {
override fun initialValue(): Lazy<T> =
lazy(LazyThreadSafetyMode.NONE, provider)
}
override val value get() = threadLocal.get().value
override fun isInitialized() = threadLocal.get().isInitialized()
}
Here's a convenience function to create instances of the delegate:
fun <T> threadLocalLazy(provider: () -> T) = ThreadLocalLazy(provider)
Then just delegate a property to threadLocalLazy { ... }. Usage example:
class Example {
val threadId by threadLocalLazy { Thread.currentThread().id }
}
fun main(args: Array<String>) {
val example = Example()
repeat(3) {
thread {
println(example.threadId) // should print three different numbers
}
}
}

Related

This in kotlin interface delegation

Is there any way to pass this when using interface delegation? This would enable nice composability - but I found no way to do this.
Means something like:
interface Foo {
}
class FooImpl(bar: Bar) : Foo {
}
class Bar: Foo by FooImpl(this) {
}
as long as FooImpl doesnt need a parameter like this it works - but it would be great to access the other class there - perhaps someone knows a way. Otherwise I would also be interested if this is worth a KEEP if not - or if it will be impossible for some reason.
Delegation doesn't support this. The delegate has to be instantiated before the class that is delegating to it, so the delegate cannot rely on it for construction. Another gotcha is that although you can override functions of the delegate, if the delegate internally calls those functions, it calls the original version, not the override. The delegate really lives in its own world.
But you could set it up for the host to pass itself to the delegate in its initialization block:
interface Foo<T> {
var host: T
fun doSomething()
}
class FooImpl : Foo<Bar> {
override lateinit var host: Bar
override fun doSomething() {
println(host.name)
}
}
class Bar(val name: String): Foo<Bar> by FooImpl() {
init {
host = this
}
}
fun main() {
val bar = Bar("Hello world")
bar.doSomething()
}
This would unfortunately expose the host to the possibility of getting disconnected from its own delegate by outside classes, though. Maybe you could make the property throw an exception if assigned more than once.
Here's a property delegate that could do that:
private class SingleAssignmentVar<T>: ReadWriteProperty<Any, T> {
private var value: T? = null
private var assigned: Boolean = false
#Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (!assigned)
error("Property has not yet been set.")
return value as T
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
if (assigned)
error("Property may only be set once.")
assigned = true
this.value = value
}
}
fun <T> Delegates.singleAssignment(): ReadWriteProperty<Any, T> = SingleAssignmentVar()
You may split your Bar class in two parts, say backend and frontend.
Frontend will be responsible for declaring interface with delegates, backend will host delegates and act as composition target.
For example:
interface Foo {
fun sayHello(): String
}
class FooImpl(val bar: BarBackend) : Foo {
override fun sayHello() = "Hello from ${bar.compositionTarget()}!"
}
class BarBackend() {
val fooImpl: FooImpl = FooImpl(this)
fun compositionTarget() = "backend"
}
class BarFrontend(backend: BarBackend) : Foo by backend.fooImpl
fun main() {
val bar = BarFrontend(BarBackend())
println(bar.sayHello())
}

Accessing the delegating receiver with by delegation in Kotlin

Given an interface:
interface Countable
{
val count: Int
}
And an implementation/factory:
fun countable(counter: () -> Int): Countable = object : Countable
{
override val count: Int
get() = counter()
}
I can implement this using the class by delegation feature:
class CountableThing : Countable by countable({ 123 })
So that this snippet predictably outputs 123:
fun main()
{
val countableThing = CountableThing()
println(countableThing.count)
}
My question is, in the context of the delegate class, is there any way to get an instance of the delegating receiver?
In other words, can my delegate Countable implementation (the anonymous object defined in fun countable) see/access the receiver instance of the CountableThing class?
I tried this:
fun <T> countable(receiver: T, counter: () -> Int): Countable = object : Countable
{
// ...
}
class CountableThing : Countable by countable<CountableThing>(this, { 123 })
But that's not valid, because expectedly:
class CountableThing : Countable by countable<CountableThing>(this, { 123 })
/^^^^
'this' is not defined in this context
No it can't, delegate objects are just objects they don't even know if they're going to be used to implement an interface through delegation. However, you can consider using delegated properties which are used to delegate properties setters and getters implementations:
class Example {
var p: String by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
then you can use
val e = Example()
println(e.p)
which prints:
Example#33a17727, thank you for delegating ā€˜pā€™ to me!
As you can see, in your delegate implementation you can use thisRef which is a reference to the object whose property is been delegated.

multiple instances of superclass member attribute

I have an abstract stub class that needs to be subclasses to add spring annotations.
abstract class ConsumerStub<TYPE>{
val receivedMessages: MutableMap<String, TYPE> = ConcurrentHashMap()
open fun processMessage(#Payload payload: TYPE, record: ConsumerRecord<String, *>) {
this.receivedMessages[record.key()] = payload
}
fun receivedMessageWithKey(key: String): Boolean = this.receivedMessages.contains(key)
fun receivedMessageWithKeyCallable(key: String): Callable<Boolean> = Callable { receivedMessageWithKey(key) }
fun getReceiveMessageWithKey(key: String): TYPE? = this.receivedMessages[key]
fun reset() {
this.receivedMessages.clear()
}
}
for example:
open class WorkflowRequestConsumerStub: ConsumerStub<InternalWorkflowRequest>() {
#KafkaListener(
id = "xyzRequestConsumerStub",
topics = ["abc-workflow-requests"]
)
override fun processMessage(
#Payload payload: InternalWorkflowRequest,
record: ConsumerRecord<String, *>
) {
super.processMessage(payload, record)
}
}
I am seeing some really weird behaviour with the receivedMessages.
After some debugging I realised there seem to be 2 instances of receivedMessages.
stub.reset() throws a null pointer exception
after changing the code to initialize receivedMessages in reset(), processMessage() and receivedMessageWithKey() are seeing 2 different receivedMessages with different objectIds.
what's going on? In java the subclass should have access to any protected members in the super, so I assume the same applies to kotlin.
UPDATE: this works as expected when defining receivedMessages abstract and override in the implementations. That really sucks if this is how it should be done in kotlin. In this case there is no need for the implementation to care about the map.

How to use code that relies on ThreadLocal with Kotlin coroutines

Some JVM frameworks use ThreadLocal to store the call context of a application, like the SLF4j MDC, transaction managers, security managers, and others.
However, Kotlin coroutines are dispatched on different threads, so how it can be made to work?
(The question is inspired by GitHub issue)
Coroutine's analog to ThreadLocal is CoroutineContext.
To interoperate with ThreadLocal-using libraries you need to implement a custom ContinuationInterceptor that supports framework-specific thread-locals.
Here is an example. Let us assume that we use some framework that relies on a specific ThreadLocal to store some application-specific data (MyData in this example):
val myThreadLocal = ThreadLocal<MyData>()
To use it with coroutines, you'll need to implement a context that keeps the current value of MyData and puts it into the corresponding ThreadLocal every time the coroutine is resumed on a thread. The code should look like this:
class MyContext(
private var myData: MyData,
private val dispatcher: ContinuationInterceptor
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
dispatcher.interceptContinuation(Wrapper(continuation))
inner class Wrapper<T>(private val continuation: Continuation<T>): Continuation<T> {
private inline fun wrap(block: () -> Unit) {
try {
myThreadLocal.set(myData)
block()
} finally {
myData = myThreadLocal.get()
}
}
override val context: CoroutineContext get() = continuation.context
override fun resume(value: T) = wrap { continuation.resume(value) }
override fun resumeWithException(exception: Throwable) = wrap { continuation.resumeWithException(exception) }
}
}
To use it in your coroutines, you wrap the dispatcher that you want to use with MyContext and give it the initial value of your data. This value will be put into the thread-local on the thread where the coroutine is resumed.
launch(MyContext(MyData(), CommonPool)) {
// do something...
}
The implementation above would also track any changes to the thread-local that was done and store it in this context, so this way multiple invocation can share "thread-local" data via context.
UPDATE: Starting with kotlinx.corutines version 0.25.0 there is direct support for representing Java ThreadLocal instances as coroutine context elements. See this documentation for details. There is also out-of-the-box support for SLF4J MDC via kotlinx-coroutines-slf4j integration module.
Though this question is quite an old one, but I would want to add to Roman's answer another possible approach with CopyableThreadContextElement. Maybe it will be helpful for somebody else.
// Snippet from the source code's comment
class TraceContextElement(private val traceData: TraceData?) : CopyableThreadContextElement<TraceData?> {
companion object Key : CoroutineContext.Key<TraceContextElement>
override val key: CoroutineContext.Key<TraceContextElement> = Key
override fun updateThreadContext(context: CoroutineContext): TraceData? {
val oldState = traceThreadLocal.get()
traceThreadLocal.set(traceData)
return oldState
}
override fun restoreThreadContext(context: CoroutineContext, oldState: TraceData?) {
traceThreadLocal.set(oldState)
}
override fun copyForChild(): TraceContextElement {
// Copy from the ThreadLocal source of truth at child coroutine launch time. This makes
// ThreadLocal writes between resumption of the parent coroutine and the launch of the
// child coroutine visible to the child.
return TraceContextElement(traceThreadLocal.get()?.copy())
}
override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext {
// Merge operation defines how to handle situations when both
// the parent coroutine has an element in the context and
// an element with the same key was also
// explicitly passed to the child coroutine.
// If merging does not require special behavior,
// the copy of the element can be returned.
return TraceContextElement(traceThreadLocal.get()?.copy())
}
}
Note that copyForChild method allows you to propagate thread local data taken from the parent coroutine's last resumption phase to the local context of the child coroutine (as Copyable in CopyableThreadContextElement implies), because method copyForChild will be invoked on the parent coroutine's thread associated with the corresponding resumption phase when a child coroutine was created.
Just by adding TraceContextElement context element to the root coroutine's context it will be propagated to all child coroutines as context element.
runBlocking(Dispatchers.IO + TraceContextElement(someTraceDataInstance)){...}
Whereas with ContinuationInterceptor approach additional wrapping can be necessary for child coroutines' builders, if you redefine dispatchers for child coroutines.
fun main() {
runBlocking(WrappedDispatcher(Dispatchers.IO)) {
delay(100)
println("It is wrapped!")
delay(100)
println("It is also wrapped!")
// NOTE: we don't wrap with the WrappedDispatcher class here
// redefinition of the dispatcher leads to replacement of our custom ContinuationInterceptor
// with logic taken from specified dispatcher (in the case below from Dispatchers.Default)
withContext(Dispatchers.Default) {
delay(100)
println("It is nested coroutine, and it isn't wrapped!")
delay(100)
println("It is nested coroutine, and it isn't wrapped!")
}
delay(100)
println("It is also wrapped!")
}
}
with wrapper overriding ContinuationInterceptor interface
class WrappedDispatcher(
private val dispatcher: ContinuationInterceptor
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
dispatcher.interceptContinuation(ContinuationWrapper(continuation))
private class ContinuationWrapper<T>(val base: Continuation<T>) : Continuation<T> by base {
override fun resumeWith(result: Result<T>) {
println("------WRAPPED START-----")
base.resumeWith(result)
println("------WRAPPED END-------")
}
}
}
output:
------WRAPPED START-----
------WRAPPED END-------
------WRAPPED START-----
It is wrapped!
------WRAPPED END-------
------WRAPPED START-----
It is also wrapped!
------WRAPPED END-------
It is nested coroutine, and it isn't wrapped!
It is nested coroutine, and it isn't wrapped!
------WRAPPED START-----
------WRAPPED END-------
------WRAPPED START-----
It is also wrapped!
------WRAPPED END-------
as you can see for the child (nested) coroutine our wrapper wasn't applied, since we reassigned a ContinuationInterceptor supplying another dispatcher as a parameter. This can lead to a problem as you can mistakenly forget to wrap a child coroutine's dispatcher.
As a side note, if you decide to choose this approach with ContinuationInterceptor, then consider to add such extension
fun ContinuationInterceptor.withMyProjectWrappers() = WrappedDispatcher(this)
wrapping your dispatcher with all necessary wrappers you have in the project, obviously it can be easily extended taking specific beans (wrappers) from an IoC container such as Spring.
And also as an extra example of CopyableThreadContextElement where thread local changes are saved in all resumptions phases.
Executors.newFixedThreadPool(..).asCoroutineDispatcher() is used to
better illustrate that different threads can be working between
resumptions phases.
val counterThreadLocal: ThreadLocal<Int> = ThreadLocal.withInitial{ 1 }
fun showCounter(){
println("-------------------------------------------------")
println("Thread: ${Thread.currentThread().name}\n Counter value: ${counterThreadLocal.get()}")
}
fun main() {
runBlocking(Executors.newFixedThreadPool(10).asCoroutineDispatcher() + CounterPropagator(1)) {
showCounter()
delay(100)
showCounter()
counterThreadLocal.set(2)
delay(100)
showCounter()
counterThreadLocal.set(3)
val nested = async(Executors.newFixedThreadPool(10).asCoroutineDispatcher()) {
println("-----------NESTED START---------")
showCounter()
delay(100)
counterThreadLocal.set(4)
showCounter()
println("------------NESTED END-----------")
}
nested.await()
showCounter()
println("---------------END------------")
}
}
class CounterPropagator(private var counterFromParenCoroutine: Int) : CopyableThreadContextElement<Int> {
companion object Key : CoroutineContext.Key<CounterPropagator>
override val key: CoroutineContext.Key<CounterPropagator> = Key
override fun updateThreadContext(context: CoroutineContext): Int {
// initialize thread local on the resumption
counterThreadLocal.set(counterFromParenCoroutine)
return 0
}
override fun restoreThreadContext(context: CoroutineContext, oldState: Int) {
// propagate thread local changes between resumption phases in the same coroutine
counterFromParenCoroutine = counterThreadLocal.get()
}
override fun copyForChild(): CounterPropagator {
// propagate thread local changes to children
return CounterPropagator(counterThreadLocal.get())
}
override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext {
return CounterPropagator(counterThreadLocal.get())
}
}
output:
-------------------------------------------------
Thread: pool-1-thread-1
Counter value: 1
-------------------------------------------------
Thread: pool-1-thread-2
Counter value: 1
-------------------------------------------------
Thread: pool-1-thread-3
Counter value: 2
-----------NESTED START---------
-------------------------------------------------
Thread: pool-2-thread-1
Counter value: 3
-------------------------------------------------
Thread: pool-2-thread-2
Counter value: 4
------------NESTED END-----------
-------------------------------------------------
Thread: pool-1-thread-4
Counter value: 3
---------------END------------
You can achieve similar behavior with ContinuationInterceptor (but don't forget to re-wrap dispatchers of child (nested) coroutines in the coroutine builder as was mentioned above)
val counterThreadLocal: ThreadLocal<Int> = ThreadLocal()
class WrappedDispatcher(
private val dispatcher: ContinuationInterceptor,
private var savedCounter: Int = counterThreadLocal.get() ?: 0
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
dispatcher.interceptContinuation(ContinuationWrapper(continuation))
private inner class ContinuationWrapper<T>(val base: Continuation<T>) : Continuation<T> by base {
override fun resumeWith(result: Result<T>) {
counterThreadLocal.set(savedCounter)
try {
base.resumeWith(result)
} finally {
savedCounter = counterThreadLocal.get()
}
}
}
}

Kotlin: How can I get the delegation class of a member property?

How can I get the delegation class of a member property?
By this, I mean is it possible to complete such a function:
inline fun <reified T> delegationExample(t: T) {
for (prop in T::class.declaredMemberProperties) {
val delegatedClass = // what to do?!
}
}
Where the delegation class may look like:
class DelegationExample {
operator fun getValue(ref: Any, prop: KProperty<*>) = 0
}
And the declaration class might look like this:
object Example {
val a by DelegationExample()
val b by DelegationExample()
val c by DelegationExample()
}
To find properties that delegate to a delegate class along with the instance of that class, here is a utility function:
data class DelegatedProperty<T : Any, DELEGATE : Any>(val property: KProperty1<T, *>, val delegatingToInstance: DELEGATE)
inline fun <reified T : Any, DELEGATE : Any> findDelegatingPropertyInstances(instance: T, delegatingTo: KClass<DELEGATE>): List<DelegatedProperty<T, DELEGATE>> {
return T::class.declaredMemberProperties.map { prop ->
val javaField = prop.javaField
if (javaField != null && delegatingTo.java.isAssignableFrom(javaField.type)) {
javaField.isAccessible = true // is private, have to open that up
#Suppress("UNCHECKED_CAST")
val delegateInstance = javaField.get(instance) as DELEGATE
DelegatedProperty(prop, delegateInstance)
} else {
null
}
}.filterNotNull()
}
A few notes:
First correct your reified type T to T: Any or you cannot access all of the extensions in Kotlin reflection including declaredMemberProperties
It is easiest to get to the field from a property reference to be sure you are actually talking about something that is really a property, so for each of declaredMemberProperties use javaField to do so.
Since javaField is a custom getter and could be nullable, it is saved to a local variable so smart casting will work later.
Then if this field has the same type as the delegation class you are looking for, you can then access the field.
But first you have to force the field's accessibility because it is a private field.
Running this in test program:
class DelegationExample {
operator fun getValue(ref: Any, prop: KProperty<*>) = 0
}
class Example {
val a by DelegationExample()
val b by DelegationExample()
val c by DelegationExample()
}
fun main(args: Array<String>) {
findDelegatingPropertyInstances(Example(), DelegationExample::class).forEach {
println("property '${it.property.name}' delegates to instance of [${it.delegatingToInstance}]")
}
}
The output is something like:
property 'a' delegates to instance of [DelegationExample#2c1b194a]
property 'b' delegates to instance of [DelegationExample#4dbb42b7]
property 'c' delegates to instance of [DelegationExample#66f57048]
One way to avoid reflection is to first initialize your delegate object and store it as a member of its own, and then delegate your property by it.
object Example {
val aDelegate = DelegationExample()
val bDelegate = DelegationExample()
val cDelegate = DelegationExample()
val a by aDelegate
val b by bDelegate
val c by cDelegate
}
On the byte code level delegated properties do not defer from regular ones (public getter/setter and a private field).
One way you could go is scanning the private fields of Example and filtering those which have operator getValue(thisRef: R, KProperty<*>). Technically a field may contain a delegate object val x = lazy {1}, but that is not very likely.