How to check Kotlin BufferedReader use { return something } has called method close()? - kotlin

My sample Kotlin about BufferedReader().use {}
I wonder if the close() is called when I return early in the use block
fun main() {
sendGet()
}
fun sendGet() {
val queryUrl = "http://www.google.com/search?q=kotlin&ie=utf-8&oe=utf-8"
val url = URL(queryUrl)
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
conn.setRequestProperty("User-Agent", "Mozilla/5.0")
val responseCode = conn.responseCode
println("Response code: ${responseCode}")
when (responseCode) {
200 -> {
println("response: ${conn.getResponseText()}")
}
else -> println("Bad response code: ${responseCode}")
}
}
private fun HttpURLConnection.getResponseText(): String {
BufferedReader(InputStreamReader(inputStream)).use {
return it.readText()
}
}

You can see the source code for use in stdlib by navigating using "Go to implementation" (Cmd + B on a Mac):
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
}
}
}
}
Because the call to close is inside the finally block, it will execute even on an early return.

Related

Kotlin: inline function and shared type

I want to call multiple API calls at once using coroutines. So far I used coroutines only to call single API call which returned result in form off success or error. Its using inline function. But I need to understand how to use this inline function parameter for data class.
Class JsonResponse is open class which is result for every single API call. But if I use T inside my data class, its red. If I use there type JsonResponse, it is returning JsonResponse type, but not that exact type what apiBlock suppose to return.
Example: apiBlock can contain task, which will return LoginResponse. LoginResponse is extending JsonResponse. But if I use JsonResponse instead T inside my data class, I will have generic JsonResponse inside my onSuccess callback.
My goal here is to initialize multiple tasks, run them inside coroutine as async, then wait for all tasks to finish and if some of them will fail, return failed ones as array so they can be called again.
Here is code what I want to achieve:
data class ApiTask(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (T)->Unit)
protected fun<T: JsonResponse> apiCallChained(
apiBlocks: List<ApiTask>,
onError: ((List<ApiTask>)->Unit),
onSuccess: ()->Unit){
val failedTasks = mutableListOf<ApiTask>()
apiBlocks.forEach { apiBlock->
launch(Dispatchers.Main){
val (r, err) = withContext(Dispatchers.IO){
try {
apiBlock.apiBlock(this) to null
} catch (e: ApiCallError) {
null to e
}
}
when {
r != null -> {
apiBlock.onSuccess(r)
}
err != null -> failedTasks.add(apiBlock)
}
}
}
if (failedTasks.isEmpty()) onSuccess.invoke() else onError.invoke(failedTasks)
}
Here is my working example for single API call:
protected fun<T: JsonResponse> apiCall(apiBlock: suspend CoroutineScope.() -> T,
onError: ((ApiCallError)->Unit)? = null,
onDone: (()->Unit)? = null,
onSuccess: suspend (T)->Unit): Job {
return launch(Dispatchers.Main){
val (r, err) = withContext(Dispatchers.IO){
try {
apiBlock() to null
} catch (e: ApiCallError) {
null to e
}
}
onDone?.invoke()
when {
r != null -> onSuccess(r)
err != null -> {
onError?.invoke(err)
}
}
}
}
Example of ApiBlock parameter value:
class ApiLogin(js: JSONObject): JsonResponse(js) {
companion object {
#Throws(ApiCallError::class)
operator fun invoke(api: AppApi, email: String, pass: String): ApiLogin{
return ApiLogin(api.apiLoginUser(email, pass))
}
}
class LoginServerResponse(js: JSONObject): JsonResponse(js){
val httpCode by JsInt("httpCode")
val session by JsString("session")
}
val r = LoginServerResponse(js)
}
This class is then used as
apiBlock = { ApiLogin(app.api, email, pass) }
UPDATE:
Fixed it like this, its working.
data class ApiTask<out T: JsonResponse>(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (#UnsafeVariance T)->Unit)
Your ApiTask also needs a generic parameter:
data class ApiTask<T : JsonResponse>(
val apiBlock: suspend CoroutineScope.() -> T,
val onSuccess: suspend (T) -> Unit
)
Then you have to add this generic parameter in the apiCallChained function too:
protected fun <T : JsonResponse> apiCallChained(
apiBlocks: List<ApiTask<T>>,
onError: ((List<ApiTask<T>>) -> Unit),
onSuccess: () -> Unit
) {
val failedTasks = mutableListOf<ApiTask<T>>()
apiBlocks.forEach { apiBlock ->
launch(Dispatchers.Main) {
val (r, err) = withContext(Dispatchers.IO) {
try {
apiBlock.apiBlock(this) to null
} catch (e: ApiCallError) {
null to e
}
}
when {
r != null -> {
apiBlock.onSuccess(r)
}
err != null -> failedTasks.add(apiBlock)
}
}
}
if (failedTasks.isEmpty()) onSuccess.invoke() else onError.invoke(failedTasks)
}

Debug is working but release not - Kotlin receives data via Bluetooth

I am working on Bluetooth receiving and sending data. I can send data via Bluetooth but it doesn't work the receive data. I want to get string data and split it. And the split data will show the list view. Since data import is not working, I created string data and called the split method, but it didn't work here either in a release. Can you help me?
Here are my Activity codes;
var mUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
var mBluetoothSocket: BluetoothSocket? = null
lateinit var mProgress: ProgressDialog
lateinit var mBluetoothAdapter: BluetoothAdapter
var mIsConnected: Boolean = false
lateinit var mAddress: String
lateinit var inputStream: InputStream
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityListBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
mAddress = intent.getStringExtra(MainActivity.EXTRA_ADDRESS).toString()
ConnectToDevice(this).execute()
run()
binding.deneme.setOnClickListener {
sendCommand("denemebeyza")
Log.d("mesajBT", "onCreate: mesaj gonderildi")
}
val string2: String = "deneme, deneme02K, deneme90,klm08B,bitti."
splitList(string2)
}
private fun sendCommand(input: String) {
if (mBluetoothSocket != null) {
try {
mBluetoothSocket!!.outputStream.write(input.toByteArray())
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun run() {
val LOGTAG: String ="ReadListString"
Log.i(LOGTAG, Thread.currentThread().name)
val buffer = ByteArray(8)
var bytes: Int
val text1: TextView = binding.text2
var readText : String
Log.d("mesajBt", "mesaj metodu")
//Loop to listen for received bluetooth messages
if (mBluetoothSocket != null) {
while (true) {
bytes = try {
bytes = inputStream.read(buffer) ?:0
readText = String(buffer, 0, bytes)
Log.e("Arduino Message", readText)
} catch (e: IOException) {
e.printStackTrace()
Log.d("Else", "message alinamadi.")
break
}
text1.text =readText
}
}
}
fun splitList(output: String) {
val listView : ListView= binding.list1
val textView: TextView= binding.text1
if (mBluetoothSocket != null) {
try {
val list: List<String> = output.split(",").toList()
var arrayAdapter: ArrayAdapter<*>
for (it in list) {
Log.e("TAG", "splitList: $list ")
val list2: ArrayList<String> = ArrayList(list)
textView.text = list2.toString()
}
arrayAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, list)
listView.adapter=arrayAdapter
} catch (e: IOException) {
e.printStackTrace()
}
// [A, B, C, D]
}
}
private class ConnectToDevice(c: Context) : AsyncTask<Void, Void, String>() {
private var connectSuccess: Boolean = true
#SuppressLint("StaticFieldLeak")
val context: Context = c
#Deprecated("Deprecated in Java")
override fun onPreExecute() {
super.onPreExecute()
mProgress = ProgressDialog.show(
context,
context.getString(R.string.connecting),
context.getString(R.string.connecting)
)
}
#SuppressLint("MissingPermission")
override fun doInBackground(vararg p0: Void?): String? {
try {
if (mBluetoothSocket == null || !mIsConnected) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
val device: BluetoothDevice = mBluetoothAdapter.getRemoteDevice(mAddress)
mBluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(mUUID)
BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
mBluetoothSocket!!.connect()
inputStream = mBluetoothSocket!!.inputStream
}
}catch (e: IOException) {
connectSuccess = false
e.printStackTrace()
}
return null
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if (!connectSuccess) {
Log.i("data", "couldn't connect")
} else {
mIsConnected = true
}
mProgress.dismiss()
}
}
}
Here is debugged console log.e output
Thanks, advance :)
I/ReadList-run: main
E/mesajBt: mesaj metodu
W/BluetoothAdapter:getBluetoothService() called with no BluetoothManagerCallback
W/libEGL: EGLNativeWindowType 0xc9a7d808 disconnect failed
W/libEGL:EGLNativeWindowType 0xc95be008 disconnect failed
I/InputMethodManager: startInputInner mService.startInputOrWindowGainedFocus E/ViewRootImpl:sendUserActionEvent() returned.
I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
Since there will be commas between words in data coming from Bluetooth, I used a comma as a separator in the split method. After some research, I corrected a few mistakes. You can change the value of the bytes as 8-16-32-64 according to the incoming data type and size.
Receive method is here
private fun run() {
//Loop to listen for received bluetooth messages
if (mBluetoothSocket != null) {
val TAG: String = "ReadList-run"
Log.i(TAG, Thread.currentThread().name)
val buffer = ByteArray(1024)
var bytes: Int
var readText: String
Log.e("mesajBt", "mesaj metodu")
while (true) {
try {
bytes = inputStream.read(buffer)
readText = String(buffer, 0, bytes)
Log.e("Arduino Message", readText)
splitlist(readText)
break
} catch (e: IOException) {
e.printStackTrace()
Log.d("Else", "message alinamadi.")
break
}
}
}
}
Here is my split method
fun splitList(output: String) {
if (mBluetoothSocket != null) {
try {
val list: List<String> = output.split(",").toList()
for (it in list) {
Log.e("TAG", "splitList: $list ")
}
} catch (e: IOException) {
e.printStackTrace()
}
// [A, B, C, D]
}
}

mockk, how to verify a specific exception is thrown

using mockk 1.9.3, junit 4
having a function which will report the exceptions for different conditions, need to test and verify the correct exception is reported.
class NetworkApi {
fun actionAndLogExceptions(appContext: Context, optionalParams: Map<String, String>) {
try {
val result = doNetWorkCall(optionalParams)
when (result) {
TIMEOUT -> {throw SocketTimeoutException(...)}
NETWORKERROR -> {throw HttpConnectionException(...)}
JSON_EROOR -> {throw JSONException(...)}
OK -> { handleResponce()}
}
} catch (ex: Throwable) {
System.out.println("+++ !!! exp:" + ex.toString())
ErrorReportManager.logHandledException(ex)
}
}
internal fun doNetWorkCall(optionalParams: Map<String, String>): String {
... ...
}
}
object ErrorReportManager {
fun logHandledException(ex: Throwable) {
... ...
}
}
the test
#Test
fun test_actionAndLogExceptions_report_exception() {
val networkApiSpy = spyk(NetworkApi::class)
every { networkApiSpy.doNetWorkCall(any(), any()) } returns JSON_EROOR. //<== test case one
mockkStatic(ErrorReportManager::class)
val spyApp = spyk(application)
networkApiSpy.actionAndLogExceptions(spyApp, HashMap())
// this any(JSONException::class) does not compile
io.mockk.verify(exactly = 1) {ErrorReportManager.logHandledException(any(JSONException::class))} //<===
//how to verify that here the JSONException
}
thanks #Raibaz help
verify {
ErrorReportManager.logHandledException(ofType(JSONException::class))
}
verify {
ErrorReportManager.logHandledException(match { it is JSONException })
}
val slot = slot<Throwable>()
verify {
ErrorReportManager.logHandledException(capture(slot))
}
assertTrue(slot.captured is JSONException)

try-with-resources / use / multiple resources

I'm using a Java-API which heavily uses the Autoclosable-Interface and thus in Java try-with-resources. However in Java you can specify
try (res1, res2, res3...) {
...
}
Do we have a way to use more than one resource? It looks like the well known callback-hell:
val database = Databases.openDatabase(dbFile)
database.use {
database.createResource(ResourceConfiguration.Builder(resPathName, config).build())
val resMgr = database.getResourceManager(ResourceManagerConfiguration.Builder(resPathName).build())
resMgr.use {
val wtx = resMgr.beginNodeWriteTrx()
wtx.use {
wtx.insertSubtreeAsFirstChild(XMLShredder.createStringReader(resFileToStore))
}
}
}
There is no standard solution for this. If you had all of the Closable instances ready at the start, you could use your own self-defined methods to handle them, like this blog post or this repository shows (and here is the discussion on the official forums that led to the latter).
In your case however, where subsequent objects rely on the previous ones, none of these apply like a regular try-with-resources would.
The only thing I can suggest is trying to define helper functions for yourself that hide the nested use calls, and immediately place you in the second/third/nth layer of these resourcs acquisitions, if that's at all possible.
For simplicity I will use A,B and C for the chained autocloseables.
import java.io.Closeable
open class MockCloseable: Closeable {
override fun close() = TODO("Just for compilation")
}
class A: MockCloseable(){
fun makeB(): B = TODO()
}
class B: MockCloseable(){
fun makeC(): C = TODO()
}
class C: MockCloseable()
Using uses
This would look like this:
A().use {a ->
a.makeB().use {b ->
b.makeC().use {c ->
println(c)
}
}
}
Making a chain use function with a wrapper
Definition
class ChainedCloseable<T: Closeable>(val payload: T, val parents: List<Closeable>) {
fun <U> use(block: (T)->U): U {
try {
return block(payload)
} finally {
payload.close()
parents.asReversed().forEach { it.close() }
}
}
fun <U: Closeable> convert(block: (T)->U): ChainedCloseable<U> {
val newPayload = block(payload)
return ChainedCloseable(newPayload, parents + payload)
}
}
fun <T: Closeable, U: Closeable> T.convert(block:(T)->U): ChainedCloseable<U> {
val new = block(this)
}
Usage
A()
.convert(A::makeB)
.convert(B::makeC)
.use { c ->
println(c)
}
This allows you to avoid having to nest deeply, at the cost of creating wrapper objects.
Method 1: For two resources and using native java resource manager:
Define jUsing() in Kotlin:
// crossinline version:
inline fun <R, A : Closeable?, B : Closeable?>
jUsing(a: A, b: B, crossinline block: (A, B) -> R): R =
J.jUsing(a, b) { c, d -> block(c, d) }
And also Util.jUsing() in Util.java:
Note: Below code is compatible with Java 9+. You can implement it with try-catch-finally to make it compatible with previous versions. See here for an example.
public static <R, A extends AutoCloseable, B extends AutoCloseable> R
jUsing(A a, B b, Function2<A, B, R> block) throws Exception {
try (a; b) {
return block.invoke(a, b);
}
}
(Function2 is kotlin.jvm.functions.Function2.)
Then use like below:
// Download url to destFile and close streams correctly:
jUsing(URL(url).openStream(), FileOutputStream(destFile), InputStream::transferTo)
Note: Above code used Java 9+ InputStream.transferTo() method. See here for a transferTo() Kotlin alternative that is compatible with previous versions.
Note: You can write Kotlin jUsing() method more simple using noinline keyword instead of crossinline. But I think crossinline version has more performance:
// noinline version:
inline fun <R, A : Closeable?, B : Closeable?>
jUsing(a: A, b: B, noinline block: (A, B) -> R): R =
Util.jUsing(a, b, block)
Method 2: For two resources (and with similar usage to method 1):
Thank #zsmb13's answer for the link
/**
* Based on https://github.com/FelixEngl/KotlinUsings/blob/master/Usings.kt
* and with some changes
*/
inline fun <R, A : Closeable, B : Closeable> using(a: A, b: B, block: (A, B) -> R): R {
var exception: Throwable? = null
try {
return block(a, b)
} catch (e: Throwable) {
exception = e
throw e
} finally {
if (exception == null) {
a.close()
b.close()
} else {
try {
a.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
try {
b.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
Method 3: For any number of resources (arrayOf(stream1, stream2, ...).use {...}):
/**
* Based on https://medium.com/#appmattus/effective-kotlin-item-9-prefer-try-with-resources-to-try-finally-aec8c202c30a
* and with a few changes
*/
inline fun <T : Closeable?, R> Array<T>.use(block: (Array<T>) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
when (exception) {
null -> forEach { it?.close() }
else -> forEach {
try {
it?.close()
} catch (closeException: Throwable) {
exception.addSuppressed(closeException)
}
}
}
}
}
See referenced link for more details.
Yet another approach for this:
val CloseableContext = ThreadLocal<MutableList<AutoCloseable>>()
inline fun scopeDef(inScope: () -> Unit) {
val oldContext = CloseableContext.get()
val currentContext = mutableListOf<AutoCloseable>()
CloseableContext.set(currentContext)
try {
inScope()
}
finally {
for(i in (currentContext.size - 1) downTo 0) {
try {
currentContext[i].close()
}
catch(e: Exception) {
// TODO: Record as suppressed exception
}
}
CloseableContext.set(oldContext)
}
}
fun <T: AutoCloseable> autoClose(resource: T): T {
CloseableContext.get()?.add(resource) ?: throw IllegalStateException(
"Calling autoClose outside of scopeDef is forbidden")
return resource
}
Usage:
class Close1(val name: String): AutoCloseable {
override fun close() {
println("close $name")
}
}
fun main(args : Array<String>) {
scopeDef {
val c1 = autoClose(Close1("1"))
scopeDef {
val c3 = autoClose(Close1("3"))
}
val c2 = autoClose(Close1(c1.name + "+1"))
}
}
Output:
close 3
close 1+1
close 1

Converting "Callable<T>" Java method to Kotlin

I'm trying to convert a Java method:
private <T> Callable<T> createCallable(final Callable<T> task) {
return () -> {
try {
return task.call();
} catch (Exception e) {
handle(e);
throw e;
}
};
}
from the following Java file ExceptionHandlingAsyncTaskExecutor.java into Kotlin.
The code gets converted automatically using IntelliJ IDEA into:
private fun <T> createCallable(task: Callable<T>): Callable<T> {
return {
try {
return task.call()
} catch (e: Exception) {
handle(e)
throw e
}
}
}
which is not correct. But I have to idea what the correct implementation for this should be. Any ideas?
I think this is an Kotlin converter bug. It converted your code to () -> T instead of Callable<T> (which is basically the same but these are actually different types).
This is the working code
private fun <T> createCallable(task: Callable<T>): Callable<T> {
return Callable {
try {
task.call()
} catch (e: Exception) {
handle(e)
throw e
}
}
}
This is how I did it, might be too verbose, but it works. I also implement a handle function.
import java.util.concurrent.*
private fun <T> createCallable(task: Callable<T>): Callable<T> {
return object : Callable<T> {
override fun call(): T {
try {
return task.call()
} catch (e: Exception) {
handle(e)
throw e
}
}
}
}
private fun handle(e: Exception): Unit { println("got exception") }
And this how I call it in a test...
fun main(vararg argv: String): Unit {
val callable1 = object : Callable<Int> {
override fun call(): Int = 1
}
val c1 = createCallable(callable1)
println("callable1 = ${c1.call()}")
val callable2 = object : Callable<Unit> {
override fun call(): Unit { println("Hello"); throw Exception("Hello") }
}
val c2 = createCallable(callable2)
c2.call()
}