Converting Java Retrofit callback to Kotlin - kotlin

I have this Java code:
Services.nfGetIncreasedRiskZones(new Callback() {
#Override
public void onResponse(Call call, Response response) {
}
#Override
public void onFailure(Call call, Throwable t) {
}
});
The service it is calling:
public static void nfGetIncreasedRiskZones(Callback callback) {
NfGetIncreasedRiskZones service = App.getRetrofitWithHeaders(App.getBaseUrl()).create(NfGetIncreasedRiskZones.class);
Call call = service.getRiskZones();
call.enqueue(callback);
}
And the NfGetIncreasedRiskZones interface:
interface NfGetIncreasedRiskZones {
#GET(Constants.NfGetIncreasedRiskZones)
Call getRiskZones();
}
The retrofit Callback interface look like this:
public interface Callback<T> {
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
}
How can I convert the first part, the "Services.nfGetIncreasedRiskZones", to Kotlin
Thank you

My best guess here is, that you are interested in how to instantiate anonymous interfaces in Kotlin and this is probably how you'd do it. Here is a quick example I hacked together on my Kotlin REPL. It's probably not the same interface you are using but it should work the same way.
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import java.io.IOException
val callback = object: Callback {
override fun onResponse(call: Call, t: Response?){
println("onResponse")
}
override fun onFailure(call: Call?, t: IOException?){
println("onFailure")
}
}
callback.onFailure(null, null) //prints "onFailure"
callback.onResponse(null, null) //prints "onSuccess"
So basically you need the object: in front of your interface and you don't need the () after the interface. The rest is more or less the same except for the slightly different syntax.
BTW: If you are sure that the parameters of the methods are never null, you don't need the ? after the parameter type.
Here I implemented a sample Service and set the anonymous callback, then run it:
class Service {
companion object {
var cb: Callback? = null
fun set(callback: Callback){
cb = callback
}
fun run() {
cb?.onResponse(null, null)
}
}
}
Service.set(object: Callback{
override fun onResponse(call: Call?, t: Response?){
println("onResponse")
}
override fun onFailure(call: Call?, t: IOException?){
println("onFailure")
}
})
Service.run() //prints "onResponse"

Related

Mock class used in a method Kotlin

I am using mockk Kotlin library. I have a service Service that has a private method calling a 3d party client
class Service {
fun foo() {
bar()
}
private fun bar() {
client = Client()
client.doStuff()
}
}
Now in my test I need to mock Client, e.g.
#Test
fun `my func does what I expect` {
}
I need to also mock what doStuff returns. How do I achieve this in Kotlin mockk?
Firstly, you should never instantiate a dependency like Client inside your service class since you cannot access it to provide a Mock. Let's deal with that first...
class Client { // this is the real client
fun doStuff(): Int {
// access external system/file/etc
return 777
}
}
class Service(private val client: Client) {
fun foo() {
bar()
}
private fun bar() {
println(client.doStuff())
}
}
and then this how to use Mockk
class ServiceTest {
private val client: Client = mockk()
#Test
fun `my func does what I expect`() {
every { client.doStuff() } returns 666
val service = Service(client)
service.foo()
}
}

Kotlin fallback wrapper

I'm looking for an elegant solution to the following.
I'd like to implement a Wrapper class that:
Accepts 2 implementations of the same Interface, and returns a new instance of that same Interface.
Any method call to the Wrapper object, tries to call the same method on the 1st implementation.
If the first call results into UnsupportedOperationException, then the 2th implementation should be used instead.
interface API {
fun getData(): String
}
class Main: API {
override fun getData(): String {
throw UnsupportedOperationException()
}
}
class Fallback: API {
override fun getData(): String {
return "data"
}
}
class Wrapper {
companion object {
fun getInstance(main: API, fallback: API): API {
// TODO
}
}
}
class Test {
#Test
fun `invokes the fallback instance`() {
val wrapper = Wrapper.getInstance(Main(), Fallback())
val response = wrapper.getData()
assertEquals(response, "data")
}
}
The best thing I have come up with so far is Delegate with Overrides:
class Wrapper(fallback: API): API by Main() {
val fallback = fallback
override fun getData(): String {
return fallback.getData()
}
}
What I don't like about this solution is that:
It requires overriding each unsupported operation
It gets quite verbose as the Interface grows into a complex multilevel structure with more sub interfaces
I'd also like to avoid Reflection for performance reasons and because this is a Kotlin Multiplatform project.
Any suggestions are appreciated.
Thanks,
Juan
Your proposed solution won't work because it will always favor the fallback for any overridden function.
There's no solution for your needs that can avoid having to manually handle every function of your interface. But you can have an intermediate function that handles the cascading selection of implementation for functions with the same signature.
class Wrapper (private val delegates: Array<out API>): API {
companion object {
fun getInstance(vararg delegates: API) = Wrapper(delegates)
}
private fun <R> delegate0Arg(function: API.() -> R): R {
for (delegate in delegates) {
try {
return delegate.function()
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override val name: String get() = delegate0Arg(API::name)
override fun getData(): String = delegate0Arg(API::getData)
}
But you would need additional functions to handle each unique number of arguments the interface functions have.
private fun <T, R> delegate1Arg(t: T, function: API.(t: T) -> R): R {
for (delegate in delegates) {
try {
return delegate.function(t)
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override fun getData(x: String) = delegate1Arg(x, API::getData)

CoroutineScope extension function in a different class

I'm trying to use an extension function to CoroutineScope to launch some asynchronous work.
I'm not sure how to call this method from my main class, see below:
class MyService {
fun CoroutineScope.getFoo() = async(IO|Single|Default) { ... }
}
class MyProgram(val service : MyService) : CoroutineScope {
fun main() {
launch {
// Doesn't work, unresloved `service.getFoo`.
val deferred = service.getFoo() getFoo
// Works, but looks a bit odd IMO.
val deferred = with(service) { getFoo() }
deferred.await()
}
}
}
I know I could just move the async {} keyword to my main method, but in this way, the caller would have to decide the scheduler.
The service knows the nature of its work (IO/Computation bound single-threaded?, etc) and I think it should be the one deciding the scheduler.
As far as I understand your intent is to let the service specify the scheduler. Why not split the specification of the scheduler and the decision to run asynchronously?
Let the service function be suspendable and use withContext to specify the scheduler.
And let the caller decide, if the function should run asynchronously.
class MyService {
suspend fun getFoo() = withContext(Dispatchers.IO) {
//work
}
}
abstract class MyProgram(val service: MyService) : CoroutineScope {
fun main() {
launch {
val deferred = async { service.getFoo() }
//some work
deferred.await()
}
}
}
Why not make getFoo a normal function and pass in the scope:
fun getFoo(scope: CoroutineScope) = scope.async {
//work }
}
launch {
service.getFoo(this)
}

Implement Retrofit's Callback interface for multiple service methods in the same class

I have an interface to generate the concrete Retrofit client class, like this:
interface SyncService {
#GET("event/sampleValue")
fun currentEvent(): Call<CurrentEventResponse>
#GET("event")
fun getEvents(): Call<List<EventResponse>>
#POST("Answer")
fun sendAnswers(#Body requests: Array<AnswerRequest>): Call<SendAnswerResponse>
}
Then I need to enqueue calls to currentEvent() and getEvents() in my ViewModel class:
class SettingsViewModel(
application: Application,
) : AndroidViewModel(application), Callback<List<EventResponse>> {
// ...
private fun getEvents() {
ApiClient.syncService().getEvents().enqueue(this)
}
fun getCurrentEventData() {
ApiClient.syncService().currentEvent().enqueue(this)
}
/**
* Failure event handler for the getEvents API request.
*/
override fun onFailure(call: Call<List<EventResponse>>, t: Throwable) {
LOGE(TAG, "getEvents API request failed.", t)
}
/**
* Response event handler for the getEvents API request.
*/
override fun onResponse(call: Call<List<EventResponse>>, response: Response<List<EventResponse>>) {
if (response.isSuccessful) {
response.body()?.let { events.addAll(it) }
}
}
}
The problem here is that I can't make SettingsViewModel class implement both Callback<List<EventResponse>> and Callback<CurrentEventResponse> as it claims that the JVM signature is the same.
One option would be create the callback object inline, like:
fun getCurrentEventData() {
ApiClient.syncService().currentEvent().enqueue(object : Callback<CurrentEventResponse> {
override fun onFailure(call: Call<CurrentEventResponse>, t: Throwable) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onResponse(call: Call<CurrentEventResponse>, response: Response<CurrentEventResponse>) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
}
But I'd like to separate the event handlers, so the calling method (getCurrentEventData()) does not grow with the logic for the onResponse and onFailure events.
What else can I do?

Typesafe map assignment and retrieval

I am trying to proxy calls for Observables and LiveData (similar to the Mediator pattern), but I could not find a typesafe solution. This is the problem:
class Proxy {
private val backupMap = HashMap<LiveData<Any>, Observer<Any>>()
fun <T> add(liveData : LiveData<T>, observer : Observer<T>) {
// !This is the issue LiveData<Any> is expected
backupMap.put(liveData, observer)
}
fun attach() {
backupMap.forEach { (key, value) ->
key.observeForever(value)
}
}
}
fun addSome() {
Proxy().apply {
add(MutableLiveData<String>(), Observer { })
}
}
I could cast backupMap.put to backupMap.put(liveData as LiveData<Any>, observer as Observer<Any>) but this causes an Unchecked Cast.
Solution I found is to use an intermediate object to hold the typesafe binding:
private val backupMap: MutableMap<LiveData<*>, Attacher<*>>
private class Attacher<A>(private val lifeData: LiveData<A>, private val observer : Observer<A>) {
fun attach() {
lifeData.observeForever(observer)
}
fun detach() {
lifeData.removeObserver(observer)
}
}