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.
Related
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.
I have a bunch of strings like these in my already existing and quit big template file:
Hello $World I say hello to $User, too
I was thinking I could somehow let kotlin parse/search&replace this file as a kotlin string, and I'd just have to set the variables World and User to get an evaluated string... How is this possible?
This is not a kotlin source file, but a file that's beeing read by my kotlin program.
Why I want to do this? I used bash's envsubst before, and had to move away from this, since things were getting too complicated. But now I have no easy way to replace strings in a file anymore...
Thanks
What you want is called a template engine.
You don't really need an eval (which would allow running a full Kotlin application from a String) in this case.
For example, FreeMarker templates use a syntax that's similar to Kotlin template Strings, so a template may look like this:
<h1>Welcome ${user}!</h1>
Then, from Kotlin, you can evaluate the template with a Map holding the template bindings (variables the template can use) like this:
val user = "joe"
val bindings = mapOf("user" to user)
val cfg = new Configuration(Configuration.VERSION_2_3_29)
cfg.directoryForTemplateLoading = File("/where/you/store/templates")
val template = cfg.getTemplate("test.ftlh")
// write the resolved template to stdout
val out = OutputStreamWriter(System.out)
template.process(bindings, out)
See a Java example here: https://freemarker.apache.org/docs/pgui_quickstart_all.html
There are many other template engines, and the KTor site lists a few:
https://ktor.io/docs/working-with-views.html
If you're using KTor, BTW, it makes it much easier to use template engines... your framework may even have similar.
Warning: Please see my other answer first: you probably don't want to run a full Kotlin script just to parse some text file with variables... use a template engine for that.
It's possible to execute Kotlin scripts, i.e. eval Kotlin code, but it requires that you basically ship the Kotlin compiler with your application.
This GitHub project, KtsRunner, for example, does that, so you can do this:
val scriptContent = "5 + 10"
val fromScript: Int = KtsObjectLoader().load<Int>(scriptContent))
println(fromScript)
// >> 15
It requires some hacking though, is very slow and it uses a bunch of Kotlin "internal" APIs to work.
See the full list of libraries this project uses here:
https://github.com/s1monw1/KtsRunner/blob/master/lib/build.gradle.kts#L21
A "proper" KEEP proposal (discussion here) exists to add first-class support for this in Kotlin, but it's not finalized yet.
Currently, it looks something like this:
fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<MainKtsScript>()
val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<MainKtsScript>()
return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, evaluationConfiguration)
}
But it'll probably change before being released.
I'm new to kotlin. Ive always used the map transform with curly braces. Then -
Why does this work ->
val x = someList.map(::SomeConstructor)
and this doesn't?
val x = someList.map{ ::SomeConstructor }
I didn't find usage of map with circular brackets anywhere on the online tutorials.
Please try to explain in detail, or provide suitable reference article.
What you ask is explained in this official documentation.
If and only if the last argument of a function is a lambda, you can extract it from the call paranthesis, to put it inline on the right of the function. It allows a nicer DSL syntax.
EDIT: Let's make an example :
One of the good use-case is context programming. Imagine you've got a closeable object. You want to delimit its usage to ensure it's properly closed once not needed anymore. In Java, you've got the try-with-resources:
try (final AutoCloseable myResource = aquireStuff()) {
// use your resource here.
}
Kotlin provide the use function. Now, you can do either :
acquireStuff().use( { doStuff1(it) ; doStuff2(it) } )
or write :
acquireStuff().use {
doStuff1(it)
doStuff2(it)
}
It looks like a Java try-w-resource, but is extensible to any of your API. Allowing you to design libraries giving advanced constructs to end-users.
When I create a client with the JacksonSerializer() feature and make some API calls, then run that script on my local machine, I get no error and the script runs successfully. However, when I upload this script as an AWS Lambda, I get the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of kotlin.coroutines.Continuation, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
At first, I thought the error originated from me constructing the client outside of the Handler class, but when I made the client a private value inside the Handler class, I still get the error. I've included println() statements in my function, but they don't even run. That tells me that my handleRequest() funciton isn't getting run. Is there some AWS/Lambda'ism that prevents me from using the JacksonSerializer() feature as? If so, are there any alternatives on how to parse JSON responses with the Ktor client?
My client construction:
private val client = HttpClient(Apache) {
install(JsonFeature) {
serializer = JacksonSerializer()
}
}
An example call using the client:
val response = client.post<JsonNode> {
url(URL(GITHUB_GRAPHQL_ENDPOINT))
body = reqBody
headers {
append("Authorization", "bearer $token")
}
}
I'm guessing that you made your handler function be a kotlin suspend function? If so, that's your problem.
When you mark a function suspend, the compiler applies a bunch of magic. Most of the time, you don't need to know anything about this, other than the fact that any suspend function gets an extra parameter of type kotlin.coroutines.Continuation added to its signature. You usually don't notice this, since the compiler also makes calls to the function pass along their own hidden Continuation parameter.
Continuation, by design, can't be created by a tool like Jackson - it's an internal thing. What you probably need to do (assuming that you did make your handler function suspend) is to wrap your method in runBlocking {} and make it not be a suspend function. It's probably easiest to create a new handler, like so:
fun fixedHandler(input: MyInput, context: Context) = runBlocking {
originalHandler(input, context)
}
suspend fun originalHandler(input: MyInput, context: Context): MyOutput {
TODO("This is your original code")
}
PS - I've usually found it best to leverage the pre-defined Lambda interfaces to write my Lambda functions - it prevents you from encountering issues like this. See https://docs.aws.amazon.com/lambda/latest/dg/java-handler-using-predefined-interfaces.html for how to do it.
Have you checked out your dependencies running locally versus your dependencies in AWS? I've had issues where locally I'm running with a version, but the version in AWS was different. That could especially explain the error about continuations... Perhaps the method signature is different in whatever version you're using?
Look especially for provided scopes in your gradle/maven pom. Those are easy places for version to be out of sync.
Java CompletableFuture<T> has a lot of async methods, static or instance, in this format
public <U> CompletableFuture<U> XXXasync(SomeFunctionalInterface<T> something, Executor executor)
If you have enough experience with FP in kotlin, you will immediately realize these function are extremely awkward to use in kotlin, because the SAM interface is not the last parameter.
aCompletableFutrue.thenComposeAsync(Function<SomeType, CompletableFuture<SomeOtherType>> {
// ^ WHAT A LONG TYPE NAME THAT NEED TO BE HAND WRITTEN
// do something that has to be written in multiple lines.
// for that sake of simplicity I use convert() to represent this process
convert(it)
}, executor)
That Function has a very very long generic signature that I don't know how to let IDE generate. It will be a plain in the butt if the type name become even longer or contains a ParameterizedType or has type variance annotations.
It also looks nasty because of the trailing , executor) on line 5.
Is there some missing functionality in kotlin or IDE that can help with the situation? At least I don't want to write that long SAM constructor all by myself.
Rejected solutions:
Using named parameter doesn't seem to work because this feature only works on a kotlin function.
Abandon async methods sounds bad from the very beginning.
Kotlin corountine is rejected because we are working with some silly Java libraries that accept CompletionStage only.
IF you calling the api from java that takes a functional interface parameter at last, you can just using lambda in kotlin.
val composed: CompletableFuture<String> = aCompletableFutrue.thenComposeAsync {
CompletableFuture.supplyAsync { it.toString() }
};
Secondly, if you don't like the java api method signature. you can write your own extension methods, for example:
fun <T, U> CompletableFuture<T>.thenComposeAsync(executor: Executor
, mapping: Function1<in T, out CompletionStage<U>>): CompletableFuture<U> {
return thenComposeAsync(Function<T,CompletionStage<U>>{mapping(it)}, executor)
}
THEN you can makes the lambda along the method.
aCompletableFutrue.thenComposeAsync(executor){
// do working
}