what list type which is mutable in kotlin can be used in java? - kotlin

Having a lib created with kotlin, in it there is a function expected to be overriden by its descendent class, which takes a mutableList (expected to be modified in this function)
protected open fun makeDataForAdapter(itemsList: MutableList<Data>) : List<Data>{
return itemsList // default behavior
}
the lib is used in a app with java, so the descendent class overrides it:
#Override
protected List<Data> makeDataForAdapter(MutableList<Data> itemsList) {
......
}
the compiler complains about "cant resolve the MutableList"
what list type which is mutable in kotlin can be used in java?

The kotlin.List<out T> and kotlin.MutableList<E> are mapped types, which, on the JVM and Android, are both represented by the java.util.List<E> interface.
So you just need to use the Java List<E> type wherever you need to inter-operate with the Kotlin List<out E> or MutableList<E>.

Related

kotlinFunction returns null if method is defined on an interface with a type parameter

A quick demo of a problem:
import kotlin.reflect.jvm.kotlinFunction
interface A<T> {
fun aaa(t: T): String {
return ""
}
}
class B : A<String>
fun main() {
println(B::class.java.methods[0].kotlinFunction) // returns null
}
Calling kotlinFunction on a method without type parameter returns an instance of KFunction as expected.
The reason is type erasure, that occurs in Java, but not in Kotlin:
Java:
public java.lang.String B.aaa(java.lang.Object)
Kotlin:
public java.lang.String B.aaa(java.lang.String)
https://github.com/JetBrains/kotlin/blob/master/core/reflection.jvm/src/kotlin/reflect/jvm/ReflectJvmMapping.kt#L134
Note that it's just Kotlin compiler preserving some more information for reflection, types will be still erased by JVM at runtime, Kotlin or not.
If you need to access Kotlin method, do it directly:
println(B::class.functions.first())

Kotlin multiplatform support for Optional

I'm working with a Java API now converted into multiplatform Kotlin. It used to use java.lang.Optional as the return type of many calls. I understand this is not the idiomatic Kotlin-way (see discussion) but this is an existing API, Optional stays (also it isn't a bad choice for the Java-facing client). My question is how?
Note: The code only needs to return Optional.of(x) or return Optional.empty() to the external API. Any internal uses will be purged.
How do we use expect/actual/typealias to use the real Optional class when available?
Is there a way to avoid re-implementing a fake Optional class on non-Java targets (i.e. work idiomatically with nullable? suffix)
At this point, Kotlin doesn't allow providing an actual typealias for an expected class with a companion object by using a Java class with matching static declarations. Follow this issue for updates: KT-29882.
For now, you can workaround that by declaring the factory functions separately, outside the expected Optional class, as follows:
expect class Optional<T : Any> {
fun get(): T
fun isPresent(): Boolean
/* ... */
}
expect object Optionals {
fun <T : Any> of(t: T): Optional<T>
fun empty(): Optional<Nothing>
}
That should not necessarily be an object, you could just use top-level functions.
Then, on the JVM, you would have to provide an actual typealias for the Optional class and, additionally, provide the trivial actual implementation for the Optionals object:
actual typealias Optional<T> = java.util.Optional<T>
actual object Optionals {
actual fun <T : Any> of(t: T): Optional<T> = java.util.Optional.of(t)
actual fun empty(): Optional<Nothing> = java.util.Optional.empty()
}
As for not providing an implementation for the non-JVM platforms, I doubt it's possible, as that would require some non-trivial compile-time transformations of the Optional usages to just the nullable type. So you would want something like this:
actual typealias Optional<T> = T?
which is now an error:
Type alias expands to T?, which is not a class, an interface, or an object
So you actually need a non-JVM implementation. To avoid duplicating it for every non-JVM target, you can declare a custom source set and link it with the platform-specific source sets, so they get the implementation from there:
build.gradle.kts
kotlin {
/* targets declarations omitted */
sourceSets {
/* ... */
val nonJvmOptional by creating {
dependsOn(getByName("commonMain"))
}
configure(listOf(js(), linuxX64())) { // these are my two non-JVM targets
compilations["main"].defaultSourceSet.dependsOn(nonJvmOptional)
}
}
}
Then, inside this custom source set (e.g. in src/nonJvmOptional/kotlin/OptionalImpl.kt) you can provide an actual implementation for the non-JVM targets.
Here's a minimal project example on Github where I experimented with the above: h0tk3y/mpp-optional-demo

why there is 'by' for the extended class and reified in function define

coming across a sample with a class and a function and trying to understand the koltin syntax there,
what does this IMeta by dataItem do? looked at https://kotlinlang.org/docs/reference/classes.html#classes and dont see how to use by in the derived class
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
IMeta by dataItem {
override fun getType(): String = dataType ?: dataItem.getType()
fun getData(): DerivedData? = getDataItem()
private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
}
for the reference, copied the related defines here:
interface IMeta {
fun getType() : String
fun getUUIDId() : String
fun getDataId(): String?
}
class DerivedData : IMeta {
override fun getType(): String {
return "" // stub
}
override fun getUUIDId(): String {
return "" // stub
}
override fun getDataId(): String? {
return "" // stub
}
}
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
There is some good documentation on reified type parameters, but I'll try to boil it down a bit.
The reified keyword in Kotlin is used to get around the fact that the JVM uses type erasure for generic. That means at runtime whenever you refer to a generic type, the JVM has no idea what the actual type is. It is a compile-time thing only. So that T in your example... the JVM has no idea what it means (without reification, which I'll explain).
You'll notice in your example that you are also using the inline keyword. That tells Kotlin that rather than call a function when you reference it, to just insert the body of the function inline. This can be more efficient in certain situations. So, if Kotlin is already going to be copying the body of our function at compile time, why not just copy the class that T represents as well? This is where reified is used. This tells Kotlin to refer to the actual concrete type of T, and only works with inline functions.
If you were to remove the reified keyword from your example, you would get an error: "Cannot check for instance of erased type: T". By reifying this, Kotlin knows what actual type T is, letting us do this comparison (and the resulting smart cast) safely.
(Since you are asking two questions, I'm going to answer them separately)
The by keyword in Kolin is used for delegation. There are two kinds of delegation:
1) Implementation by Delegation (sometimes called Class Delegation)
This allows you to implement an interface and delegate calls to that interface to a concrete object. This is helpful if you want to extend an interface but not implement every single part of it. For example, we can extend List by delegating to it, and allowing our caller to give us an implementation of List
class ExtendedList(someList: List) : List by someList {
// Override anything from List that you need
// All other calls that would resolve to the List interface are
// delegated to someList
}
2) Property Delegation
This allows you to do similar work, but with properties. My favorite example is lazy, which lets you lazily define a property. Nothing is created until you reference the property, and the result is cached for quicker access in the future.
From the Kotlin documentation:
val lazyValue: String by lazy {
println("computed!")
"Hello"
}

Kotlin default arguments in interface bug?

kotlin file
interface Test {
fun test(message: String, delay: Int =100)
}
class A: Test
{
override fun test(message: String, delay: Int) {
}
}
I find i can't use #JvmOverloads in interface nor class.
if i add a #JvmOverloads in interface,the error is #JvmOverloads annotation cannot be used on interface method,if i add #JvmOverloads in class,the error is platform declaration clash....
However, I seem able to use defaults paramters in kotlin files,like this.
var a=A()
a.test("1234")
But when I use it in a java file, it seems that the method is not overloaded。
A a=new A();
a.test("123");//Compile error
The following version without interface can work
class A
{
#JvmOverloads
fun test(message: String, delay: Int=100) {
}
}
Then I can use it normally in java file
A a=new A();
a.test("123");
But how to maintain the same functionality after add the interface?
This is not a bug. #JvmOverloads annotation simply does not work with abstract methods.
From Kotlin docs:
Normally, if you write a Kotlin function with default parameter values, it will be visible in Java only as a full signature, with all parameters present. If you wish to expose multiple overloads to Java callers, you can use the #JvmOverloads annotation.
The annotation also works for constructors, static methods etc. It can't be used on abstract methods, including methods defined in interfaces.
source: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-generation
Why?
Because as You can learn from the doc I mentioned, #JvmOverloads instructs compiler to generate bunch of Java overloaded methods, omitting each of the parameters one by one, starting from the last one.
As far as I understand, each overloaded method calls internally method with one more parameter, and this additional parameter has default value. Edit: see comment by #hotkey here
This won't work with abstract methods, because they don't have any body.
Also new Java interface would have more methods, and its implementations would have to implement all of them. Kotlin interface had only one method.
To get to the same result you can make a LegacySupport class in Kotlin that will actually call the function with the default parameter and then you can expose only the return of the function to the java class from this class.

Converting Kotlin's KClass to regular Class in Java

I am trying call a regular Java method in a Java code as follows:
public <T> T proxy(KClass<T> kClass) {
// unfortunately nothing like getJavaClass() exists
return (T) proxy(kClass.getJavaClass());
}
public <T> T proxy(Class<T> jClass) {
return (T) context.getBean(jClass);
}
In Kotlin, you can call .java on each KClass. This is not the case here and I am unable to extract the Java Class object from KClass. Is there a way to do it?
EDIT: This is trivial in Kotlin, but I am looking for solution in Java code.
The functionality does exist, just not where it seems to, as java is an extension property.
Use the method JvmClassMappingKt.getJavaClass.
In Kotlin, extension methods (and property getters/setters) are implemented as static methods of their containing class. If you look at the source for .java (Ctrl+Q), you can see that it is implemented in JvmClassMapping.kt.
As the function is package-level and does not have a containing object, it is simply placed into the file [Filename]Kt which in this case is JvmClassMappingKt.
Here is the source of this extension property:
#Suppress("UPPER_BOUND_VIOLATED")
public val <T> KClass<T>.java: Class<T>
#JvmName("getJavaClass")
get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
As you can see, the method's name is renamed on the JVM to getJavaClass.
In your case, you can try:
public <T> T proxy(KClass<T> kClass) {
return (T) proxy(JvmClassMappingKt.getJavaClass(kClass));
}
You can try to use javaObjectType on your KClass
The explanation:
Returns a Java [Class] instance corresponding to the given [KClass] instance.
In case of primitive types it returns corresponding wrapper classes.
E.g.
Boolean::class.javaObjectType