Can't compile Kotlin Jackson Extensions readValue(File) - kotlin

I am trying to use Kotlin Jackson extensions to do JSON conversions in my code. But for some reason, I am getting a syntax error when trying to use the readValue(File) function.
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3'
---
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
...
private val objectMapper = jacksonObjectMapper()
...
val factionList: List<Faction> = objectMapper.readValue<List<Faction>>(
File(javaClass.classLoader.getResource("data/factions.json").file))
The error I get from the compiler is:
None of the following functions can be called with the arguments supplied.
readValue(JsonParser!, ResolvedType!)
...
[it lists all the valid function signatures ...]
However, none of the extension functions seem to be showing up in that list. If I click on the function and hit Cmd-B in IntelliJ, I am seeing the readValue(File) method in the extensions code.
I am confused why the function is not being found by the compiler.

You're most likely missing the following import:
import com.fasterxml.jackson.module.kotlin.readValue
Forgot this a few times myself.

Related

How can I tell the Kotlin compiler that a Java method will never return null?

I don't or can't modify the Java source code. The goal to configure just the Kotlin compiler to know what is nullable and what isn't.
You can specify the type manually if you know something will never be null. For example, if you have the following Java code:
public static Foo test() {
return null;
}
and you call it in Kotlin like this:
val result = Foo.test()
then result will have a type of Foo! by default – which means it can be either Foo or Foo?.. the compiler doesn't have enough information to determine that.
However, you can force the type manually:
val result: Foo = Foo.test()
// use "result" as a non-nullable type
Of course, if at runtime that is not true, you'll get a NullPointerException.
For reference, please check the documentation.
I don't know of a way to configure the compiler for this, but IntelliJ IDEA has a feature that allows you to add annotations to code via an XML file called external annotations.
You can add the Jetbrains #Nullable and #NotNull annotations to library code, but when I've tried it, it only results in compiler warnings rather than errors when you use incorrect nullability in your code. These same annotations generate compiler errors when used directly in the source code. I don't know why there is a difference in behavior.
You can use extension functions for this. If you have a method String foo() in the class Test, you can define the extension function
fun Test.safeFoo(): String = this.foo()!!
The advantage is that the code is pretty obious.
The disadvantage of this approach is that you need to write a lot of boiler plate code. You also have to define the extension function in a place where all your modules or projects can see it. Also, writing that much code just to avoid !! feels like overkill.
It should also be possible to write a Kotlin compiler extension which generates them for you but the extension would need to know which methods never return null.

Kotlin - Overload resolution ambiguity. All these functions match

I am trying to add a global state store to my topology, but getting error as
Overload resolution ambiguity. All these functions match.
val stateStoreBuilder =
Stores.keyValueStoreBuilder(
Stores.persistentKeyValueStore("my_global_store"),
Serdes.String(),
Serdes.String()
)
topology.addGlobalStore(
stateStoreBuilder,
"source_name",
KEY_JSON_DE,
VALUE_JSON_DE,
"topic_name",
"processor_name",
{ MyStoreProcessor::class.java },
)
Getting error for addGlobalStore method.
Using below versions in Gradle file :-
kotlin("jvm") version "1.7.10"
kotlin("plugin.spring") version "1.7.10"
implementation("org.apache.kafka:kafka-streams:3.3.1")
implementation("org.springframework.kafka:spring-kafka")
I think the problem is shows in the small letter of the error.
The Kotlin compiler cannot figure out which method to use. In particular to what class it should map the last lambda, to org.apache.kafka.streams.processor.ProcessSupplier or org.apache.kafka.streams.processor.api.ProcessSupplier (notice the later has an api package in the middle).
I reckon that if you cast the lambda, it should work. I've never tried this, but I wonder if changing the line to the following would work
{ MyStoreProcessor::class.java } as org.apache.kafka.streams.processor.api.ProcessSupplier

Unable to reference kotlinx.cinterop package in Kotlin Multiplatform project

I created a Kotlin Multiplatform project based on the example for iOS and Android (https://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html). Within my iOS target, I am using cinterop to link in a 3rd party Objective-C framework. This is working fine. I am able to reference the framework classes in my Kotlin code within the 'iosMain' source set. However, one of the method calls requires an NSError** parameter. I am attempting to use the following to create this variable in my Kotlin code:
kotlinx.cinterop.NativePlacement.allocPointerTo<kotlinx.cinterop.ObjCObjectVar<platform.Foundation.NSError?>()
I have not been able to find away around the following errors:
> Task :sharedLib:linkMainDebugFrameworkIOS FAILED
src/iosMain/kotlin/Platform.kt:9:50: error: unresolved reference: allocPointerTo
val error = kotlinx.cinterop.NativePlacement.allocPointerTo<kotlinx.cinterop.ObjCObjectVar<platform.Foundation.NSError?>()
^
src/iosMain/kotlin/Platform.kt:9:126: error: no value passed for parameter 'rawPtr'
val error = kotlinx.cinterop.NativePlacement.allocPointerTo<kotlinx.cinterop.ObjCObjectVar<platform.Foundation.NSError?>()
My understanding is that this package is part of stdlib, which should be added as a dependency automatically. Am I missing a piece of the equation somewhere?
UPDATE
The following is an example of passing an NSError* reference from Kotlin:
memScoped {
val errorRef = alloc<ObjCObjectVar<NSError?>>()
someObjCObject.method(errorRef.ptr)
}
kotlinx.cinterop.NativePlacement is an interface name, not a class name. You need an instance of the NativePlacement interface to work. For example memscoped{..} block will work, e.g.
import kotlinx.cinterop.*
import platform.Foundation.*
val p = memScoped {
allocPointerTo<ObjCObjectVar<NSError?>>()
}
The memscoped{..} accepts a lambda, inside the lambda the receiver implements the NativePlacement type, so there is no need for a qualifier to call a function on it
https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver

Jinq in Kotlin - how to convert lambda into java SerializedLambda?

Can I have serializable lambda in Kotlin? I am trying to use Jinq library from Kotlin, but it requires serializable lambdas. Is there any syntax that makes it possible?
Update:
My code:
var temp=anyDao.streamAll(Task::class.java)
.where<Exception,Task> { t->t.taskStatus== TaskStatus.accepted }
.collect(Collectors.toList<Task>());
I am getting this error:
Caused by: java.lang.IllegalArgumentException:
Could not extract code from lambda.
This error sometimes occurs because your lambda references objects that aren't Serializable.
All objects referenced in lambda are serializable (code results in no errors in java).
Update 2
After debugging it seems that kotlin lambda isn't translated into java.lang.invoke.SerializedLambda which is required by Jinq to get information from. So the problem is how to convert it to SerializedLambda.
I'm the maker of Jinq. I haven't had the time to look at Kotlin-support, but based on your description, I'm assuming that Kotlin compiles its lambdas into actual classes or something else. As such, Jinq would probably need some special code for cracking open Kotlin lambdas, and it may also need special code for handling any unusual Kotlin-isms in the generated code. Jinq should be capable of handling it because it was previously retrofitted to handle Scala lambdas.
If you file an issue in the Jinq github about it, along with a small Kotlin example (in both source and .class file form), then I can take a quick peek at what might be involved. If it's small, I can make those changes. Unfortunately, if it looks like a lot of work, I don't think I can really justify putting a lot of resources into adding Kotlin support to Jinq.
I have no experience on Jinq, but according to the implementation in GitHub and my experience of using Java Library in Kotlin.
ref: https://github.com/my2iu/Jinq/blob/master/api/src/org/jinq/orm/stream/JinqStream.java
You can always fall back to use the native Java Interface in Kotlin.
var temp = anyDao.streamAll(Task::class.java)
.where( JinqStream.Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
// Alternatively, You you can import the interface first
import org.jinq.orm.stream.JinqStream.*
...
// then you can use Where instead of JinqStream.Where
var temp = anyDao.streamAll(Task::class.java)
.where(Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
Or make a custom extension to wrap the implementation
fun JinqStream<T>.where(f: (T) -> Boolean): JinqStream<T> {
return this.where(JinqStream.Where<T,Exception> { f(it) })
}
Disclaimer: The above codes have not been tested.

Kotlin: Why can't I use one of my functions?

I am trying to use one of my defined functions that accepts a string yet the software won't compile.
fun passes(address: String) = Collections.frequency(addresses, address) <= CONNECTIONS_PER_IP
fun passes(remoteAddress: InetSocketAddress) = passes(remoteAddress.hostName)
I can't even call the string function using a custom string, for example passes("127.0.0.1").
None of the following functions can eb called with the arguments supplied.
passes(String) defined in abendigo.Firewall
passes(InetSocketAddress) defined in abendigo.Firewall
I presume you're using java.lang.String instead of kotlin.String in the Kotlin source code. Please use only kotlin.String instead, this is the type that string literals in Kotlin have (but in the bytecode it's still transformed to java.lang.String).
The issue was an import of java.lang.String. For some reason IntelliJ imported it.