Kafka Streams Materialized View with Kotlin - kotlin

To create a kafka streams state store in Java I can do this:
final KGroupedStream<String, String> wordCounts = textLines
.flatMapValues(value -> Arrays.asList(pattern.split(value.toLowerCase())))
.groupBy((key, word) -> word);
wordCounts.count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as(WORD_COUNT_STORE));
I am attempting to convert this to Kotlin, like this:
val wordCounts: KGroupedStream<String, String> = textLines
.flatMapValues({value -> value.split("\\W+") })
.groupBy({ _, word -> word})
wordCounts.count(Materialized.<String, Long, KeyValueStore<Bytes, Array<Byte>>>as(WORD_COUNT_STORE))
However, I get the following compiler error:
Interface KeyValueStore does not have constructors
What do I need to do?

In case it's of use to anyone else, as well as the backticks suggested by Raman, I had to make couple of other changes:
First, the generic types need to be specified after the as method, not straight after the Materialized class.
Secondly, rather than using Array<Byte> I had to use ByteArray.
So the full line of code that worked for me was:
wordCounts.count(Materialized.`as`<String, Long, KeyValueStore<Bytes, ByteArray>>(WORD_COUNT_STORE))

Since as is a reserved word in Kotlin, try surrounding the as with backticks i.e.
`as`

Related

How to write `$("user")` in kotlin with flink

from flink 1.14, it suggest using $() for retrieving elements like below:
Table table = tableEnv.fromDataStream(ds, $("user"), $("product"), $("amount"));
so is there a way to convert it to kotlin, for it causing compiler error in kotlin:
var table = tableEnv.fromDataStream(ds, $("user"), $("product"), $("amount"));
I am not familiar with Apache Flink, but you're not allowed to use the dollar sign on it's own.
For function names with special characters, e.g. whitespace, you have to put the function name into backticks (`), e.g.:
fun `white space`() = Unit
fun `$`() = Unit
fun main() {
`white space`()
`$`()
}
Thus, your code example above works on my machine with the following adjustments.
import org.apache.flink.table.api.Expressions.*
...
val table = tableEnv.fromDataStream(ds, `$`("user"), `$`("product"), `$`("amount"))
This problem will be fixed in one of the next Flink releases:
https://issues.apache.org/jira/browse/FLINK-26278

How to use KotlinPoet to get correct TypeName for PropertySpec

Using KotlinPoet, in order to generate a PropertySpec for adding properties to classes and constructors, you need a TypeName object.
The TypeMirror.asTypeName() KotlinPoet function is deprecated, because it won't always work correctly for Kotlin types.
But I can't find a single example of how to get a correct TypeName for a Kotlin class (e.g. kotlin.String) using the kotlinpoet-metadata APIs, the way the deprecation message says.
The docs for kotlinpoet-metadata APIs also seem completely broken (go to https://square.github.io/kotlinpoet/interop-kotlinx-metadata/#interop-with-kotlinx-metadata and click anything under the APIs section)
Does anyone have an example of how to replace TypeMirror.asTypeName() with some kotlinpoet-metadata code to get a TypeName, so that I can create a PropertySpec?
Not very sure if this aligns with the intention of the deprecation message, but this is what I got it to work.
I first had to add kotlinpoet-metadata-specs.
implementation("com.squareup:kotlinpoet:1.7.1")
implementation("com.squareup:kotlinpoet-metadata:1.7.1")
implementation("com.squareup:kotlinpoet-metadata-specs:1.7.1")
Then use a util method from com.squareup.kotlinpoet.metadata.specs.internal.ClassInspectorUtil to create className.
val packageName = getPackage(element).qualifiedName.toString()
val typeMetadata = element.getAnnotation(Metadata::class.java)
val kmClass = typeMetadata.toImmutableKmClass()
val className = ClassInspectorUtil.createClassName(kmClass.name)
then use
val funSpec = FunSpec.builder("allNullableSet")
.receiver(className)
.returns(Boolean::class.java)
.addStatement(statement)
.build()
I have found a way to get the TypeName of a TypeElement in my AbstractProcessor, thanks to having access to its processingEnv:
val kmClass = (typeElement.kotlinClassMetadata() as KotlinClassMetadata.Class).toKmClass()
val elementName: TypeName = ClassName(processingEnv.elementUtils.getPackageOf(typeElement).toString(), kmClass.name.substringAfterLast("/"))
It should also be doable without processingEnv by splitting the kmClass.name manually.

Kotlin: Difference between {} and () while using map transform?

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.

LiveData map transformations in kotlin

Transformations.map in LiveData transformations take two arguments :
#NonNull LiveData source
#NonNull final Function func
I tried to make the function like this:
val localLiveData = #some live data of type LiveData<User>
Transformations.map(localLiveData, s->{return s.name = "Hi"})
but this shows error cannot unresolved "s"
finally i got it working by this :
Transformations.map(localLiveData) {
s.name = "Hi"
return#map s
}
How this thing is working map has only one argument? (noob in kotlin)
Most of the problems here are with Kotlin's lambda syntax, which is slightly different from that of some other languages.
In Kotlin, a lambda must have braces.  But the -> is optional in some cases (if the lambda takes no parameters; or if it takes one and you're referring to it with the dummy name it).
This is one reason why your first version fails; it would need the s -> moved inside the braces.  (Another is that in Kotlin, an assignment is not an expression, and doesn't return a value, so you can't use it in a return.)
Your second works because in Kotlin, if the last parameter is a lambda, it can be moved outside the parenthesis.  (This allows for higher-order functions that look like language syntax.  In fact, if the lambda is the only parameter, you can omit the parentheses entirely!)
I don't know LiveData, but I wonder if the return#map is doing the right thing: it will return not just from the lambda, but from the map() method itself.  (Such non-local returns aren't needed very often, and can be confusing.)
Also, a lambda doesn't need an explicit return; it returns the value of its last expression.
So I suspect that a more concise version would be:
Transformations.map(localLiveData) { it.name = "Hi"; it }

Is there a better way to write CompletableFutrue.XXXasync() invocations in kotlin?

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
}