Coroutines with LiveData - android-room

Get compilation error when try to run the below code :
The code success fully run if i changed the return type to List, but i wanted to return the live data object from the suspended function.
#Dao
interface TodoDao {
#Query("SELECT * from Todo where category_name = :category_name")
suspend fun getAllTodo(category_name : String) :LiveData<List<Todo>>
}
Compiler throws error: Not sure how to convert a Cursor to this method's return type (LiveData<List<Todo>>).
public abstract java.lang.Object getAllTodo(#org.jetbrains.annotations.NotNull()
def room_version = '2.1.0-beta01'
//Room
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
//View model
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-beta01'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1"
Any help will be appreciated.
Thank you

remove suspend cuz it is already suspend function when you said return LiveData
Your code looks like:
suspend suspend fun getAllTodo(category_name : String) :LiveData<List<Todo>>
here is correct one:
fun getAllTodo(category_name : String) :LiveData<List<Todo>>
but if you will use repository, then there you need write suspend, but not in DAO, don't forget use, for example in ViewModel, coroutines:
viewModelScope.launch(Dispatchers.IO){
...dao.getAllTodo(category_nam)...
}

Related

Redis transaction in Spring Boot + Kotlin

I am trying to execute a transaction on a Redis instance from within Spring Boot application written in Kotlin. I have followed the recommendation in Spring Doc on the best practice to achieve this.
I am struggling with the Kotlin implementation, however. Specifically, I don't know how to implement the Java generic interface with a generic method to make it work in the Kotlin code:
redisTemplate.execute(object : SessionCallback<List<String>> {
override fun <K : Any?, V : Any?> execute(operations: RedisOperations<K, V>): List<String>? {
operations.multi()
operations.opsForValue().set("key", "value")
return operations.exec()
}
})
The code above complains that the set method expects parameters with types K and V respectively but String is found instead.
Is there an elegant way how to inline the interface implementation in Kotlin without having to use unchecked casting or other convoluted approaches to make this work?
I think you're facing this problem due to poor interface definition for SessionCallback and the framework itself is doing unsafe casts themselves.
You see, if we take a look into the SessionCallback definition over here we can see that it looks as follows:
public interface SessionCallback<T> {
#Nullable
<K,V> T execute(RedisOperations<K,V> operations) throws DataAccessException
}
The generics K,V referring to the type of keys and values from your Redis are not parameters of the SessionCallback interface and that's why the kotlin compiler is having a hard time inferring the type of these: Because the execute function only takes a parameter of type SessionCallback<T> without passing the types of keys and values as parameters to that interface.
Your best-effort might be to provide a nice wrapper around that API using extension functions and inline generic types by doing some controlled unsafe casts.
Something like this might be enough:
inline fun <reified K : Any?, reified V: Any?, reified T> RedisTemplate<K, V>.execute(crossinline callback: (RedisOperations<K,V>) -> T?): T?{
val callback = object : SessionCallback<T> {
override fun <KK, VV> execute(operations: RedisOperations<KK,VV>) = callback(operations as RedisOperations<K, V>) as T?
}
return execute(callback)
}
Which then you can consume by doing:
fun doSomething(redisTemplate: RedisTemplate<String, String>) {
redisTemplate.execute { operations ->
operations.multi()
operations.opsForValue().set("key", "value")
operations.exec() as List<String>
}
}
And yes, you need to cast the .exec() result because nobody bothered using generics and returns a List<Object> as you can see on the official documentation

Returning values into GlobalScope launch using Spring

I have an endpoint exposed, that is launching a coroutine:
val apiCall = ApiCall()
#GetMapping("/example")
fun example(#RequestParam paramExample:String):Int{
GlobalScope.launch{
return apiCall.callApi(paramExample)
}
}
This function is calling another external API, using Retrofit:
suspend fun callApi(param:String):Int{
var tot_records =0
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(appProperties.sampleUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create<ResponseService>(ResponseService::class.java)
service.getResponse().enqueue(object : Callback<Response> {
override fun onFailure(call: Call<Response>, throwable: Throwable) {
println("Error")
println(throwable.stackTrace)
}
override fun onResponse(call: Call<Response>, response: Response<Response>) {
println("OK")
println(response.body())
println("Tot records")
tot_records = response.body()?.tot_records!!
}
})
return tot_records
}
The problem is that I can't launch this, the error is: 'return' is not allowed here
Any idea how to fix it and whats is happening?
Thanks for your help
It seems like you can't decide if you want your code to be synchronous (so code waits for its subtasks to finish before continuing) or asynchronous (it launches operations in the background). You intend to return a result from example(), so you need it to be synchronous, but you immediately use launch() to invoke callApi() asynchronously. The same in callApi() - you intend to return from it (so synchronous), but you invoke Retrofit using callbacks (so asynchronous). Note that callApi() has exactly the same problem as example(). Even if it compiles, it still does not really work properly. It always returns 0, because tot_records is returned before being set.
You have to decide between asynchronous and synchronous and stick to it. If you want to go fully asynchronous, then you need to redesign both callApi() and example() to return their results either with callbacks or futures.
However, I suggest going fully synchronous, utilizing Kotlin suspend functions. Make all functions suspend: example(), callApi() (it is already) and ResponseService.getResponse(). The last one will look something like:
suspend fun getResponse(): Response
Then remove GlobalScope.launch(), and almost everything inside enqueue(). Instead, service.getResponse() will return Response object directly, so you can just return its tot_records property.
Also note that in your original code you ignored failures. After above change service.getResponse() will throw exceptions on failures, so you have to handle them.
This solution seems that works:
This is the endpoint declaration:
#GetMapping("/example")
suspend fun example(#RequestParam param:String):CustomResponse{
return coroutineScope {
val job = async{apiCall.callApi(param)}
job.await()
}
}
And this is my function that is calling an external API:
suspend fun callApi(param:String):CustomResponse{
var responseCustom = CustomResponse()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(appProperties.reservationUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create<CustomResponseService>(CustomResponseService::class.java)
responseCustom = service.getResponse(appProperties.token, param).execute().body()!!
return responseCustom
}

How to return single object from Reactive REST API in Kotlin Coroutine style

I am trying to convert a REST service from the Spring 5 Reactive style to an async Kotlin Coroutine style.
I followed several different guides/tutorials on how this should work but I must be doing something wrong.
I get a compile error trying to turn a single object into a Flow, whereas the guides I'm following dont seem to do this at all.
Any pointers or otherwise very appreciated!
Router:
#Bean
fun mainRouter(handler: EobHandler) = coRouter {
GET("/search", handler::search)
GET("/get", handler::get)
}
Handler:
suspend fun search(request: ServerRequest): ServerResponse {
val eobList = service.search()
return ServerResponse.ok().bodyAndAwait(eobList)
}
suspend fun get(request: ServerRequest): ServerResponse
val eob = service.get()
return ServerResponse.ok().bodyAndAwait(eob); // compile error about bodyAndAwait expecting a Flow<T>
}
Service:
override fun search(): Flow<EOB> {
return listOf(EOB()).asFlow()
}
//
override suspend fun get(): EOB? {
return EOB()
}
If curious, here are some of the guides I've based my code on:
https://www.baeldung.com/spring-boot-kotlin-coroutines
https://docs.spring.io/spring/docs/5.2.0.M1/spring-framework-reference/languages.html#how-reactive-translates-to-coroutines
https://medium.com/#hantsy/using-kotlin-coroutines-with-spring-d2784a300bda
I was able to get this to compile by changing
return ServerResponse.ok().bodyAndAwait(eob);
to
return eob?.let { ServerResponse.ok().bodyValueAndAwait(it) } ?: ServerResponse.notFound().buildAndAwait()
guess it's something to do with type-safety of Kotlin - I was not returning a nullable object I think

Calling a function of a spyk'd data class

I have a data class A with a function as follows:
data class A(val a: String) {
fun foo(b: String) = "$a, $b"
}
I attempt the following mock in my test:
fun `whatever`() {
val spy = spyk<A>()
every { spy.a } returns "Tree"
assertThat(spy.foo("Snake")).isEqualTo("Tree Snake")
}
When I run a test written like this it fails with a NullPointerException on the line fun foo... in the data class.
Am I doing anything wrong or is this a bug in MockK?
I have totally different results when I run your code. Firstly it complains that there is no default constructor.
Then I fixed it to use the non-default constructor and it prints "abc Snake"
val spy = spyk(A("abc"))
every { spy.a } returns "Tree"
println(spy.foo("Snake"))
There is a reason for that. Kotlin is accessing a property through a field in foo function. This seems to be an optimization.
MockK is not able to do anything about it right now. There is the following ticket to transform getfield call: https://github.com/mockk/mockk/issues/104

Kotlin not able to convert gradle's Action class to a lambda

So, while this is quite a kotlin-dsl for gradle specific issue, I think it overall applies to the kotlin language itself, so I am not going to use that tag.
In the gradle API, the class Action<T> is defined as:
#HasImplicitReceiver
public interface Action<T> {
/**
* Performs this action against the given object.
*
* #param t The object to perform the action on.
*/
void execute(T t);
}
So ideally, this should work in kotlin (because it is a class with a SAM):
val x : Action<String> = {
println(">> ${it.trim(0)}")
Unit
}
But I get the following two errors:
Unresolved reference it
Expected Action<String> but found () -> Unit
Fwiw, even Action<String> = { input: String -> ... } doesn't work.
Now here's the really intriguing part. If I do the following in IntelliJ (which btw, works):
object : Action<String> {
override fun execute(t: String?) {
...
}
}
IntelliJ pops the suggestion Convert to lambda, which when I do, I get:
val x = Action<String> {
}
which is better, but it is still unresolved. Specifying it now:
val x = Action<String> { input -> ... }
gives the following errors Could not infer type for input and Expected no parameters. Can someone help me with what is going on?
This is because the Action class in gradle is annotated with HasImplicitReceiver. From the documentation:
Marks a SAM interface as a target for lambda expressions / closures where the single parameter is passed as the implicit receiver of the invocation (this in Kotlin, delegate in Groovy) as if the lambda expression was an extension method of the parameter type.
(emphasis mine)
So, the following compiles just fine:
val x = Action<String> {
println(">> ${this.trim()}")
}
You could even just write ${trim()} and omit the this in front of it.
You need reference the function with class name, like:
val x: Action<String> = Action { println(it) }

Resources