I am trying to learn Kotlin and delegates are both interesting and confusing. I have a situation where, in a java class I would take a constructor arg, create a Future (the ID represents a resource in another system) and stash the Future as an instange variable. Then the "getXXX" would call Future.get()
Here is a sample java class
public class Example {
private Future<Foo> foo;
public Example(String fooId) {
this.foo = supplyAsync(() -> httpClient.get(fooId));
}
public Foo getFoo() {
return foo.get();
}
}
I am not supplying the Kotlin example because I am simply not sure how to construct it.
You can translate your Java code to Kotlin in a straightforward way using custom property getters:
class Example(fooId: Int) {
private val fooFuture = supplyAsync { httpClient.get(fooId) }
val foo: Foo
get() = fooFuture.get()
}
But Kotlin has a more powerful concept for generalizing property behavior -- the property delegates:
class Example {
val foo: Foo by someDelegate
}
In this example, someDelegate is an object that defines the behavior of property foo.
Though Future<V> cannot be used as a delegate out of the box in Kotlin, you can create your own property delegates by implementing getValue(thisRef, property) and (for mutable properties) setValue(thisRef, property, value) functions, thus explicitly providing the code to be executed when a property is read (and written, if mutable).
These functions can be either member functions for your project classes or extension functions, which fits the case with Future<V>. Basically, to use Future<V> as a property delegate, you have to define the getValue(thisRef, value) extension function for it, for example:
operator fun <V> Future<V>.getValue(thisRef: Any?, property: KProperty<*>) = get()
Here, the value the delegate will provide for a property will be simply taken from the Future::get call, but a proper implementation should probably take care of cancellation and exceptions handling. For this purpose, you can wrap a Future<V> into a class that will also define the fallback values/strategies, and then use this class' objects in by.
Then you can use Future<V> objects as delegates for your properties:
class Example(fooId: Int) {
val foo: Foo by supplyAsync { Thread.sleep(2000); fooId }
}
fun main(args: Array<String>) {
val e = Example(123)
println(e.foo)
}
To complete the answer from hotkey I propose this solution for a ReadWrite property
fun <V> Future<out V>.asDelegate(mayInterruptIfRunning: Boolean = false) =
object : ReadWriteProperty<Any?, V> {
private val lock = Object()
private var completedOrCanceled: Boolean = false
private var mValue: V? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
synchronized(lock) {
if (!completedOrCanceled) {
mValue = get()
completedOrCanceled = true
}
}
#Suppress("UNCHECKED_CAST")
return mValue as V
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
synchronized(lock) {
if (!completedOrCanceled) {
cancel(mayInterruptIfRunning)
completedOrCanceled = true
}
mValue = value
}
}
}
Usage could be :
class Example(fooId: Int) {
var foo: Foo by supplyAsync { Thread.sleep(2000); print("job done "); fooId }.asDelegate()
}
fun main(args: Array<String>) {
val e = Example(123)
println(e.foo) //"job done 123" printed after 2 sec
val f = Example(123)
f.foo = 456 //without waiting
println(e.foo) //"456" printed immediately
//"job done " printed after 2 sec
val g = Example(123) //"job done " printed after 2 sec
Thread.sleep(3000) //wait 3 sec then
println(e.foo) //"123" printed immediately
g.foo = 456
println(e.foo) //"456" printed immediately
}
note that if mayInterruptIfRunning is set to true then "job done " won't be printed if f.foo = 456 is called before the 2 sec
Related
I have an authorizaton Aspect that checks specific conditions based on method annotation.
This specific example shows annotation to mark a method that is only accessible by customer service. But unfortunately this isn't the only condition.
We have to confirm the customerServiceId that is also passed as one of method parameters. The parameter containing customerServiceId is pretty nested, so I was wondering if it's possible to get parameter value by some kind of a "path".
So let's say we have this method:
fun updateRemoteConfig(val remoteConfig: RemoteConfig) { doSomething() }
RemoteConfig class is pretty nested, so the path to customerServiceId would be something like: remoteConfig.customerService.id
What I would like to achieve is mark the method with annotation:
#CustomerServiceAccess(customerServiceIdPath = "remoteConfig.customerService.id")
And the value would then be fetched inside Aspect method. But I have no idea how to get to the specified value by path. Is it even possible?
The unknown is where arrows are in the code. Here's rest of the aspect:
#Aspect
class AuthorizationAspect {
#Pointcut("#annotation(com.my.project.annotations.CustomerServiceAccess)")
fun customerServiceAccess() = Unit
#Before("customerServiceAccess()")
fun checkAccess(joinPoint: JoinPoint) {
val methodSignature = joinPoint.signature as MethodSignature
val method = methodSignature.method
val canAccess = mutableListOf<() -> Boolean>()
.apply {
addAll(method.getAnnotationsByType(CustomerServiceAccess::class.java).map { it.canAccess(method) })
}
.any { it() }
if (!canAccess) {
throw UnauthorizedException(message = "User cannot perform this action")
}
}
private fun CustomerServiceAccess.canAccess(val method: Method): () -> Boolean = {
->> val customerServiceIdParam = method.getParameterByPath(getCustomerServiceIdPath())
SecurityContext.isCustomerService && SecurityContext.customerServiceId == customerServiceIdParam
}
private fun CustomerServiceAccess.getCustomerServiceIdPath(): String = this.customerServiceIdPath
}
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.FUNCTION)
annotation class CustomerServiceAccess(val customerServiceIdPath: String)
Is there a way to register a codec for multiple classes? Basically, all my classes should just be serialized using a Jackson object mapper. But it seems like I have to create a custom codec for each class (even though I can abstract it a little bit using generics).
A small code example:
Codec:
class JacksonCodec<T>(private val mapper: ObjectMapper, private val clazz: Class<T>) : MessageCodec<T, T> {
override fun encodeToWire(buffer: Buffer, s: T) {
buffer.appendBytes(mapper.writeValueAsBytes(s))
}
override fun decodeFromWire(pos: Int, buffer: Buffer): T {
val length = buffer.getInt(pos)
val bytes = buffer.getBytes(pos + 4, pos + 4 + length)
return mapper.readValue(bytes, clazz)
}
...
}
register codec for each class I want to serialize:
vertx.eventBus()
.registerDefaultCodec(A::class.java, JacksonCodec(DatabindCodec.mapper(), A::class.java))
vertx.eventBus()
vertx.eventBus()
.registerDefaultCodec(B::class.java, JacksonCodec(DatabindCodec.mapper(), B::class.java))
vertx.eventBus()
The code examples are kotlin but same applies for Java.
As far as I can tell looking at the code, there is no way, as the class needs to be the exact match:
https://github.com/eclipse-vertx/vert.x/blob/master/src/main/java/io/vertx/core/eventbus/impl/CodecManager.java#L99
It is possible, with some limitations and quirks. I would not recommend doing it.
Let's start with the limitations:
It can not be used in clustered mode
You have to declare the codec name every time you send something over the eventbus.
If you create a generic codec that encodes classes with Jackson and every time you send something over the eventbus you make sure to add it using codecName in the deliveryOptions, you can register it only once and use it for all of your classes.
Full example:
fun main() {
val vertx = Vertx.vertx()
vertx.eventBus().registerCodec(GenericCodec())
vertx.eventBus().consumer<Foo>("test-address") {
println(it.body())
it.reply(Bar(), genericDeliveryOptions)
}
vertx.eventBus().request<String>("test-address", Foo(), genericDeliveryOptions) {
println(it.result().body())
}
vertx.close()
}
data class Foo(
val foo: String = "foo",
)
data class Bar(
val bar: String = "bar",
)
class GenericCodec : MessageCodec<Any, Any> {
companion object {
const val NAME = "generic"
}
private val mapper: ObjectMapper = ObjectMapper()
override fun encodeToWire(buffer: Buffer, s: Any) {
buffer.appendBytes(mapper.writeValueAsBytes(s))
}
override fun decodeFromWire(pos: Int, buffer: Buffer): Any {
throw RuntimeException("should never get here, unless using clustered mode")
}
override fun transform(s: Any): Any {
return s
}
override fun name(): String {
return NAME
}
override fun systemCodecID(): Byte {
return -1
}
}
val genericDeliveryOptions = deliveryOptionsOf(codecName = GenericCodec.NAME)
I have this arraylist of GameObjects. I loop through the arraylist, and if the type of the object is door (one of the GameObject's child classes), and if some other conditions match up, i want to call a function from the door class thats only in that class. Is this possible? I'm using Kotlin, but if you only know java i could probably port it.
You can use is, as? or with operators combined with smart casts for that.
In java you can code as below:
for (GameObject gameObject: GameObjects) {
if(gameObject instanceof Door ) { // you can add your another condition in this if itself
// your implementation for the door object will come here
}
}
You can use like this:
//Kotlin 1.1
interface GameObject {
fun age():Int
}
class GameObjectDoor(var age: Int) : GameObject{
override fun age():Int = age;
override fun toString():String = "{age=$age}";
}
fun main(args: Array<String>) {
val gameObjects:Array<GameObject> = arrayOf(
GameObjectDoor(1),
GameObjectDoor(2),
GameObjectDoor(3));
for (item: GameObject in gameObjects) {
when (item) {
is GameObjectDoor -> {
var door = item as GameObjectDoor
println(door)
//do thomething with door
}
//is SomeOtherClass -> {do something}
}
}
}
Given the following class (written in kotlin):
class Target {
fun <R> target(filter: String, mapper: (String) -> R): R = mapper(filter)
}
I'm able to test in java, the test code:
#Test
public void testInJava() {
Target mockTarget = Mockito.mock(Target.class);
Mockito.when(mockTarget.target(
argThat(it -> true),
Mockito.argThat(it -> true)
)).thenReturn(100);
assert mockTarget.target("Hello World", it -> 1) == 100;
}
The java test pass as expected, but the same test is written in kotlin:
#Test
fun test() {
val mockTarget = Mockito.mock(Target::class.java)
Mockito.`when`(mockTarget.target(
Mockito.argThat<String> { true },
mapper = Mockito.argThat<Function1<String, Int>>({ true }))
).thenReturn(100)
assert(mockTarget.target("Hello World") { 1 } == 100)
}
The kotlin version I receive the following exception:
java.lang.IllegalStateException: Mockito.argThat<String> { true } must not be null
Why is it happening and how can I test that using kotlin?
I also faced the same problem.
And finally, I found argThat() will return null, and normally the argument in the function in kotlin, does not accept null type.
The source code of argThat from ArgumentMatchers.java
public static <T> T argThat(ArgumentMatcher<T> matcher) {
reportMatcher(matcher);
return null;
}
You can see that it return null. So when we mock the function, it will throw IllegalStateException, because argThat returns null and argument can't be null.
It mean that if your function is:
fun doSomething(arg1: String): Int {
// do something
}
When you mock it like that:
Mockito.`when`(
doSomething(Mockito.argThat<String> { true })
).thenReturn(100)
It will throw IllegalStateException
So you should change your function like that:
fun doSomething(arg1: String?): Int {
// do something
}
Change the "String" to "String?", make it accept null type.
My solution is to define the argument with class? so that it can accept null, but I don't know if it is a great solution
In 2022, Mockito-Kotlin officially solves the problem.
The fix is very simple: Just import the argThat/eq/... from the mockito-kotlin package, instead of the mockito package, and everything is done!
Related: https://github.com/mockito/mockito-kotlin/wiki/Mocking-and-verifying
As of this writing, mockito-kotlin hasn't been updated for more than a year. As with all of these libraries, there's always a constant need for keeping them up-to-date, and I didn't want to get stuck with an unmaintained library.
So I came up with another way to solve the null issue with argThat without using any other libraries.
Say we've an interface UuidRepository as follows:
interface UuidRepository {
suspend fun Entity save(entity: Entity): Entity
}
class Entity has two properties, userId: String and uuid: String.
The following code fails:
Mockito.verify(uuidRepository).save(argThat { it.userId == someValue && it.uuid == "test" })
with the error:
argThat { it.userId == someValue && it.uuid == "test" } must not be null
To solve this, we get all the invocation on the mock and then verify the ones we want:
val invocations = Mockito.mockingDetails(uuidRepository).invocations
.filter { setOf("findById", "save").contains(it.method.name) }
.map { it.method.name to it.arguments }
.toMap()
assertThat(invocations).containsKey("save")
val first = invocations["save"]?.first()
assertThat(first).isNotNull
val entity = first as Entity
assertThat(entity.userId).isEqualTo(someValue)
assertThat(entity.uuid).isEqualTo("test")
I'm currently designing database for a mobile application. Recently I found very useful function to access database in background:
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
Besides that I figured out that don't need synchronization code as the database will be accessed only in one thread (i.e the thread used by SingleThreadExecutor).
The only issue is that the following methods have to be restricted to be invoked only through ioThread function (or using IO_EXECUTOR).
abstract class MyDatabase : RoomDatabase() {
companion object {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
Is it possible to achieve this in Kotlin/Java?
UPDATE: for now I have this implementation but think there should be better ones
// App.kt file
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
private var IO_THREAD_ID: Long = -1L
private fun getIOThreadId(): Long {
if (IO_THREAD_ID == -1L)
IO_THREAD_ID = IO_EXECUTOR.submit(Callable<Long> { Thread.currentThread().id }).get()
return IO_THREAD_ID
}
fun notInIOThread() = Thread.currentThread().id != getIOThreadId()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
and then use notInIOThread() in init() and getInstance() functions
If you absolutely need to make sure that the code is running on the correct thread, you could make use of a custom thread and then checking Thread.currentThread() for the interface.
private interface MarkedIOThread // Marker interface
private val IO_EXECUTOR = Executors.newSingleThreadExecutor { r ->
return object : Thread(r), MarkedIOThread
}
fun notInIOThread(): Boolean = Thread.currentThread() !is MarkedIOThread
Yes, you can use android annotations`s Worker Thread annotation.
When you annotate a method or class with #WorkerThread, android will give you lint errors if you call it from the UI thread.
You can read more about the #WorkerThread here: https://developer.android.com/reference/android/support/annotation/WorkerThread
And more about android annotations here: https://developer.android.com/studio/write/annotations
I would suggest that you should check room library: https://developer.android.com/topic/libraries/architecture/room
It is very powerful, if you don't have any specific reason to create a database library, room is your best bet.
I assume you want the functions to be called only inside ioThread code block, otherwise there'd be a type error. First make them member functions of a class with user-code-inaccessible constructor so others cannot call it directly:
class MyDslClass internal constructor() {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
And ioThread should be:
fun ioThread(f : MyDslClass.() -> Unit) {
val dsl = MyDslClass()
IO_EXECUTOR.execute { dsl.f() }
}
Then you can restrict calls to those functions only inside ioThread block.
fun main(args: Array<String>) {
ioThread {
getInstance() // Ok
}
// cannot call `getInstance` since I cannot construct a `MyDslClass`
}