While loop nested under synchronized block in Kotlin - while-loop

Why the following does compile in Kotlin:
fun foo(): Boolean {
while (true) {
return true
}
}
fun bar(): Boolean {
synchronized("") {
return foo()
}
}
while the following doesn't?
fun baz(): Boolean {
synchronized("") {
while (true) {
return true
}
}
}
And what is the idiomatic way to make the latter function to compile? I can rewrite it as follows:
fun baz(): Boolean {
synchronized("") {
while (true) {
return true
}
TODO("Never")
}
}
-- but it doesn't look elegant enough.

Related

How can I transform Unit object to DTO object?

I am trying to change my code to strategy pattern using spring boot and kotlin, but I can not return my object list in function into Service. How can i transform the output of my forEach which is a Unit to an list of Object DTO which is what my function should actually return? Below are the codes:
interface RecommendationStrategy {
fun validateCorrect(amount: BigDecimal, asset: Asset?, reasonId: Int?): Boolean
fun send(): List<ProductDto>
}
#Component
class StrategyA(
private val serviceHelper: ServiceHelper
) : RecommendationStrategy {
override fun validateCorrect(amount: BigDecimal, asset: Asset?, reasonId: Int?): Boolean {
if (/* logical conditions */) {
return true
}
if (/* logical conditions */) {
return true
}
return false
}
override fun send(): List<ProductDto> {
return serviceHelper.getProducts().filter { it.id!! == 3L || it.id == 1L }
.map { serviceHelper.getlProductMap(it) }.sortedByDescending { it.id }
}
}
#Component
class StrategyB(
private val serviceHelper: ServiceHelper
) : RecommendationStrategy {
override fun validateCorrect(amount: BigDecimal, asset: Asset?, reasonId: Int?): Boolean {
if (/* logical conditions */)) {
return true
}
if (/* logical conditions */) {
return true
}
if (/* logical conditions */) {
return true
}
return false
}
override fun sendLoan(): List<ProductDto> {
return serviceHelper.getProducts().filter { it.id!! == 1L }
.map { serviceHelper.getProductMap(it) }
}
}
#Service
class RecommendationService(
private val recommendationStrategy: List<RecommendationStrategy>,
private val serviceHelper: ServiceHelper
) {
#Transactional(readOnly = true)
fun getProductsRecommended(amount: BigDecimal, asset: Asset?, reasonId: Int?): List<ProductDto> {
val result =
recommendationStrategy.forEach { if (it.validateCorrectLoan(amount, asset, reasonId)) it.send() }
}
}

Kotlin idiomatic way to check a condtion and do something if fail

converting java to kotlin,
java code
private boolean hasEndpoint() {
if (mSettings == null || mSettings.getEndpoint() == null) {
if (isDebugMode()) {
throw new IllegalArgumentException("endpoint is not set !!!");
}
return false;
}
return true;
}
public void doAction_1(...) {
if (!hasEndpoint()) {
callback.onError(ENDPOINT_UNINITIALIZED, "ERROR_END_POINT_NOT_SET");
return;
}
//do the action with valid endpoint
doSomething_1(mSettings.getEndpoint());
}
the kotlin:
private fun hasEndpoint(): Boolean {
if (mSettings?.endpoint == null) {
require(!isDebugMode) { "endpoint is not set !!!" }
return false
}
return true
}
fun doAction_1() {
if (!hasEndpoint()) {
callback.onError(ENDPOINT_UNINITIALIZED, "ERROR_END_POINT_NOT_SET")
return
}
//do the action with valid endpoint
doSomething_1(mSettings!!.getEndpoint());
}
There are multiple functions (i.e. doAction_1(), doAction_2() ...) doing the same check using hasEndpoint().
What is Kotlin idiomatic way to do something like this?
You can use a concept similar to Python decorators:
// Add your check here
fun withCheck(action: () -> Unit) {
if (!hasEndpoint()) {
callback.onError(ENDPOINT_UNINITIALIZED, "ERROR_END_POINT_NOT_SET")
return
}
action()
}
// Add your actions enclosed with `withCheck`
fun action1() = withCheck {
doSomething_1(mSettings!!.getEndpoint());
}
fun action2() = withCheck {
doSomething_2(mSettings!!.getEndpoint());
}
You can use a property instead of a function for hasEndpoint or rather hasNoEndpoint and use when in place of if else
private val hasNoEndpoint: Boolean
get() = when {
mSettings?.endpoint != null -> false
isDebugMode -> throw IllegalArgumentException("endpoint is not set !!!")
else -> true
}
// use this in withCheck function as in enzo's answer
fun withEndpoint(action: () -> Unit): Unit = when {
hasNoEndpoint -> callback.onError(ENDPOINT_UNINITIALIZED, "ERROR_END_POINT_NOT_SET")
else -> action()
}

Difference between using `invokeOnCompletion` and `try-catch`

As the title implies, I am curious if there's any difference between doing this;
fun main() {
val job = GlobalScope.launch(Dispatchers.Main) {
withTimeout(2000L) {
delayMe()
}
}
job.invokeOnCompletion { cause -> println("We were canceled due to $cause") }
}
suspend fun delayMe() {
withContext(Dispatchers.Default) {
delay(5000L)
}
}
or this;
fun main() {
GlobalScope.launch(Dispatchers.Main) {
try {
withTimeout(2000L) {
delayMe()
}
} catch(cause: Exception){
println("We were canceled due to $cause")
}
}
...
}
...
in terms of handling exceptions inside coroutines.
PS: The sample code above is inspired from here.

How to execute a defined function after each function in Kotlin

I am writing Espresso unit test code.
What I want to do is taking screenshot on every actions without specifying
takeSpoonScreenshot("")
This is my AndroidJUnit4 Testcode:
#Test
fun givenVideoDetail_whenChooseCurrentItem_thenShowCountLabel() {
pickerPage {
clickFirstVideoItem()
}
videoDetailPage {
clickSelectCheckBox()
assertCountLabel()
}
}
and this is my VideoDetailPage.kt:
fun videoDetailPage(func: VideoDetailPage.() -> Unit) = VideoDetailPage.apply {
assertFirstPage()
func()
}
fun screenshotAfterAction(func: VideoDetailPage.() -> Unit) = VideoDetailPage.apply {
func()
takeSpoonScreenshot("")
}
object VideoDetailPage : BaseActions() {
// Write 'How to test' here
fun assertFirstPage() {
resourceIsDisplayed(R.id.send_balloon_image)
resourceIsDisplayed(R.id.media_detail_item_check_box)
resourceIsDisplayed(R.id.video_editor_mute_btn)
}
fun clickFilterButton() = takeScreenshotAfterFunction {
clickButton(R.id.image_editor_filter)
}
fun clickSelectCheckBox() {
clickButton(R.id.media_detail_item_check_box)
}
fun assertFilterSelectionListIsOpen() {
resourceIsDisplayed(R.id.media_filter_list)
}
fun assertCountLabel() {
resourceIsDisplayed(R.id.media_editor_selected_count)
}
}
See that I made takeScreenshotAfterFunction, but It is not proper because I should write takeScreenshotAfterFunction N times.

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()
}