Sonar cube is reporting critical issue - Possible null pointer dereference in ...getByName(String) due to return value of called method. How can I fix this ?
class UnitRepository(private val database: Database) : IUnitRepository {
override fun getByName(name: String): Either<DatabaseError, UnitEntity> {
val unit: UnitEntity?
return try {
unit = database.units.find { it.name eq name }
if (unit == null) {
Either.Left(MissingEntityError(UnitEntity::class.java, "name"))
} else {
Either.Right(unit)
}
} catch (e: Exception) {
Either.Left(DatabaseError(e.message))
}
}
}
Related
I am writing a generic function to retrieve data. It fetches from redis first, if there is no cache, then fetches from supplier (database).
However it returns List<LinkedHashMap> instead of generic type List<T>.
fun <T>retrieveWithCaching(
indices: List<Long>,
cacheKeyPrefix: String,
supplier: (List<Long>) -> List<T>
): List<T> {
if (indices.isEmpty()) {
return listOf()
}
val cacheKey = cacheKeyPrefix + indices.joinToString(",")
val cached = stringRedisTemplate.opsForValue().get(cacheKey)
if (cached != null) {
try {
return jacksonObjectMapper().readValue(cached) // here returns List<LinkedHashMap>
} catch (e: Exception) {
e.printStackTrace()
}
}
val records = supplier(indices)
if (records.isNotEmpty()) {
try {
val cache = jacksonObjectMapper().writeValueAsString(records)
stringRedisTemplate.opsForValue().set(cacheKey, cache, 30, TimeUnit.MINUTES)
logger.info("Cached for $cacheKey")
} catch (e: Exception) {
e.printStackTrace()
}
}
return records
}
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)
now i am learning Room in https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#11
and i can not understand the code
INSTANCE?.let { database ->
scope.launch {
populateDatabase(database.wordDao())
}
}
why does INSTANCE.let block exist
what is different that
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
scope.launch {
populateDatabase(database.wordDao())
}
}
this is full code
#Database(entities = arrayOf(Word::class), version = 1, exportSchema = false)
abstract class WordRoomDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
private class WordDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
INSTANCE?.let { database ->
scope.launch {
populateDatabase(database.wordDao())
}
}
}
suspend fun populateDatabase(wordDao: WordDao) {
wordDao.deleteAll()
wordDao.insert(Word("Hello"))
wordDao.insert(Word("World!"))
}
}
companion object {
#Volatile
private var INSTANCE: WordRoomDatabase? = null
fun getDatabase(
context: Context,
scope: CoroutineScope
): WordRoomDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WordRoomDatabase::class.java,
"word_database"
).addCallback(WordDatabaseCallback(scope))
.build()
INSTANCE = instance
return instance
}
}
}
}
.let { } is a scoping function. Scoping functions allow us to write concise code. Let examine this little code:
INSTANCE: represents the instance of your Room database.
? : says, "if the value is not null"
scope represents a scope on which a Coroutine runs.
INSTANCE?.let { it -> }: says that (look at the question mark above), if INSTANCE is not null, create a scope which exposes a copy of the non-null INSTANCE. itis just a default name, you can name it to anything just like a variable.
So:
INSTANCE?.let { database -> //database (or 'it') is not null
scope.launch {
populateDatabase(database.wordDao()) //Now pre-populate the database.
}
}
Generally speaking, this code
INSTANCE?.let { database ->
scope.launch {
populateDatabase(database.wordDao())
}
}
is just a more elegant way to write this:
if (INSTANCE != nil) {
scope.launch {
populateDatabase(INSTANCE!!.wordDao())
}
}
I have the following problem that I am already working on for over 20 hours: I want to use an Event Channel to get a data stream from the Spotify SDK. On the native side, I can automatically display the status of a current song by subscribing to my PlayerState. My goal is to be able to access this data stream with my Flutter app. On the native side I can output the data flow without problems. But I also want to be able to access this data in my Flutter App. The problem is that I do not get the data from Kotlin to Dart. I can not execute the command mEventSink?.success(position) because the mEventSink is zero.
It would be really great if someone could help me with this problem.
//...
class Spotifysdk04Plugin(private var registrar: Registrar): MethodCallHandler, EventChannel.StreamHandler {
//...
private var mEventSink: EventChannel.EventSink? = null
companion object {
#JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "spotifysdk")
channel.setMethodCallHandler(Spotifysdk04Plugin(registrar))
val eventChannel = EventChannel(registrar.messenger(), "timerStream")
eventChannel.setStreamHandler(Spotifysdk04Plugin(registrar))
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "loginAppRemote") {
//...
} else if(call.method == "initEventStream") {
try {
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
Log.d("test", "test24")
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition1", position.toString())
if(mEventSink != null) {
Log.d("test", "test25")
mEventSink?.success(position)
} else {
Log.d("test", "mEventSink == null")
}
}
} catch (err:Throwable) {
Log.v("initEventStreamError",err.message.toString())
result.success(false)
}
} else {
result.notImplemented()
}
}
override fun onCancel(arguments: Any?) {
mEventSink = null
}
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink) {
mEventSink = eventSink
}
}
I found a solution:
override fun onListen(p0: Any?, p1: EventChannel.EventSink?) {
mEventSink = p1
Log.d("test", "test1")
if(spotifyAppRemote == null) {
Log.d("test", "test2")
}
val connectionParams = ConnectionParams.Builder(clientId)
.setRedirectUri(redirectUri)
.showAuthView(true)
.build()
SpotifyAppRemote.connect(registrar.context(), connectionParams, object : Connector.ConnectionListener {
override fun onConnected(appRemote: SpotifyAppRemote) {
spotifyAppRemote = appRemote
if(spotifyAppRemote != null) {
Log.d("test", "test3")
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
Log.d("test", "test24")
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition1", position.toString())
if(mEventSink != null) {
Log.d("test", "test25")
mEventSink?.success(position)
} else {
Log.d("test", "mEventSink == null")
}
}
}
Log.d("Spotify App Remote Login", "Connected!")
}
override fun onFailure(throwable: Throwable) {
Log.e("Spotify App Remote Login", "Error!", throwable)
}
})
}
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()
}