Why does changing dispatcher in catch block throw VerifyError - kotlin

I want to understand why this exception is thrown when I use withContext() with Dispatchers.Main or Dispatchers.IO in catch block.
Here's my code:
init {
viewModelScope.launch {
try {
throw RuntimeException("whatever")
} catch (e: Exception){
withContext(Dispatchers.MAIN) {
e.printStackTrace()
}
}
}
}
This code throws java.lang.VerifyError
Verifier rejected class xx.xxxx.ErrorViewModel: java.lang.Object
xx.xxxx.ErrorViewModel$1.invokeSuspend(java.lang.Object)
failed to verify: java.lang.Object
xx.xxxx.ErrorViewModel$1.invokeSuspend(java.lang.Object):
[0x3D] register v4 has type Reference: java.lang.Exception but expected
Precise Reference: kotlin.jvm.internal.Ref$ObjectRef
(declaration of 'xx.xxxx.ErrorViewModel$1' appears in
/data/app/xx.xxxx-9pkI5L5NB9qa1CWUxAapUw==/base.apk!classes2.dex)

You should never see a VerifyError; this probably indicates a bug in the compiler.
I'd suggest raising an issue on the JetBrains YouTrack site.

Related

kotlin coroutineScope exception cannot be handled

Hi I'm playing around kotlin and I want to catch and throw our the exception, so my code is like this
runBlocking {
coroutineScope {
nonNullRecords.forEach {
launch(Dispatchers.IO) {
val time = measureTimeMillis {
try {
process(it)
} catch (e: Exception) {
throw Exception(e)
}
}
}
}
}
}
the process function is s suspend function.
So the thing is that in this case, if the process function has an exception(which is HttpTimeoutException), my service will crash which is excepted. But if I don't use the try catch, then my service will ignore the exception.
and further more, if I use throw e instead of throw Exception(e), it will also ignore the exception
May I know how this works? thanks so much
This is because Ktor's HttpRequestTimeoutException extends CancellationException, which is an exception used internally by coroutines to implement the cancellation mechanism. This is why this particular exception is not considered a real problem and is silently ignored.
This was fixed and will be released in Ktor 2.0.0:
https://youtrack.jetbrains.com/issue/KTOR-3192

Catch Exception and prevent it from propogating to parent scope in Kotlin Coroutines

Background: I am fetching data from Bluetooth and after every packet is received it is processed. What I am trying to do is to start timeout when data processing finishes and stop the timer when a new packet is received.
Tried creating a timeout logic using Flow. I created a short snippet to test if it works:
class ExceptionPropagationTest {
#Test
fun test()= runBlocking {
println(get(coroutineContext))
}
suspend fun get(coroutineContext: CoroutineContext) = withContext(coroutineContext) {
try {
enableDataTransferTimeout()
delay(3000)
"Result"
} catch (e: IllegalStateException) {
println("Exception caught ${System.currentTimeMillis()}")
"No Result"
}
}
private fun CoroutineScope.enableDataTransferTimeout() {
flowOf("1").onEach {
delay(500)
doSomething()
throw IllegalStateException()
}.launchIn(this)
}
private suspend fun doSomething(){
// Do some suspending work
}
}
Above code first prints:
Exception caught [CURRENT_TIME]
Then logs exceptions stack trace and crashes:
java.lang.IllegalStateException at
com.app.ExceptionPropagationTest$enableDataTransferTimeout$1.invokeSuspend(ExceptionPropagationTest.kt:49)
(Coroutine boundary) at
com.app.ExceptionPropagationTest$test$1.invokeSuspend(ExceptionPropagationTest.kt:32)
Caused by: java.lang.IllegalStateException
Question: Is there any way to catch the exception and return value without propagating the exception to parent scope?
If it is not possible with flow any other solution or suggestion is welcome.
You can use the catch method. Docs here
flowOf("1")
.map {
delay(500)
doSomething()
throw IllegalStateException()
}
.catch { ... } // catches exceptions in map or other operands you applied
.collect()

Kotlin, MockK: How to verify that a method call throws an exception with MockK?

I am learning Kotlin and MockK. I have seen how to verify that a method was called and how to check the result. But how would I check, that the method has thrown an exception?
Sorry, I found it: assertFailsWith<EceptionClass> { methodCall() }
This is my approach, hope its helping you
class TestClass {
fun testVerify() {
throw Exception("exception")
}
}
#Test
fun mockTest() {
try {
TestClass().testVerify()
}
catch (e: Exception) {
assertEquals(e.message, "exception")
}
}

Stop library from swallowing all exceptions in Kotlin

I'm writing an app in Kotlin that uses a third party library which does some asynchronous work, and then passes the result back to my code in a callback. The problem is that the library wraps the callback in a generic try-catch block so any exceptions my code then throws is swallowed by the library.
Is there a way to catch my exceptions without changing to a different thread? I've tried wrapping my code in a runBlocking and a withContext but exceptions are still caught by the library
You should try to handle exceptions yourself in the code block which is passed to the library, then you can return them as a callback result.
Something like this:
fun <T> libraryCall(block: () -> Result<T>): Result<T> {
TODO()
}
sealed class Result<out T> {
class Data<T>(val data: T) : Result<T>()
class Error(val ex: Exception) : Result<Nothing>()
}
fun main() {
val result = libraryCall {
return#libraryCall try {
Result.Data(5)
} catch (e: Exception) {
Result.Error(e)
}
}
}
The best solution I found is to use a CoroutineExceptionHandler.
val handler = CoroutineExceptionHandler { _, exception ->
// This will crash the app rather than have the library swallow it
throw exception
}
// Callback on some thread
GlobalScope.launch(Dispatchers.IO) {
GlobalScope.launch(handler) {
throw RuntimeException("My code has thrown an exception")
}.join()
}

Should I handle exception with Closable.use{...} in Kotlin?

According to the source of Closable.use, if an error occurs, an exception will be thrown.
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when {
apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
this == null -> {}
exception == null -> close()
else ->
try {
close()
} catch (closeException: Throwable) {
// cause.addSuppressed(closeException) // ignored here
}
}
}
In most examples of Closable.use, try-catch is not used as shown below.
Why isn't error handling needed? Is it safe?
BufferedReader(FileReader("test.file")).use { return it.readLine() }
This line
BufferedReader(FileReader("test.file")).use { return it.readLine() }
is not safe. Reading and closing the reader can both throw IOExceptions, which are not RuntimeExceptions (caused by programming errors). That means leaving them uncaught exposes your app to crashing from things outside your control.
Since Kotlin doesn't have checked exceptions, the compiler won't warn you about this. To do this safely, you need to wrap it in try/catch. And if you want to handle read errors differently than close errors, you either need to have inner and outer try/catch statements:
try {
BufferedReader(FileReader("test.file")).use {
try {
return it.readLine()
catch (e: IOException) {
println("Failed to read line")
}
}
} catch (e: IOException) {
println("Failed to close reader")
}
or wrap the whole thing and extract any suppressed exceptions, but then its cumbersome to distinguish between them:
try {
BufferedReader(FileReader("test.file")).use { return it.readLine() }
} catch (e: IOException) {
val throwables = listOf(e, *e.suppressed)
for (throwable in throwables)
println(throwable.message)
}
But in practice, you're probably not going to react differently to various IOExceptions, so you can just put the one try/catch outside.
We see from Kotlin documentation what is the purpose of the use function:
Executes the given block function on this resource and then closes it
down correctly whether an exception is thrown or not.
This function closes the resource properly if the block function completed successfully or threw an exception. It is your responsibility to handle the result of the block function.
If an exception was thrown and there is a way to handle it and proceed with code execution, use a try/catch. If there is nothing to do about it and control should be passed to the caller, it is not necessary to use a try/catch.