#JvmOverloads error on kotlin interface companion object function - kotlin

Cannot use #JvmOverloads on kotlin interface companion object function, even an #JvmStatic on it:
interface Foo {
companion object {
#JvmStatic
#JvmOverloads
fun bar(a: Int = 1, b: Int = 2){}
}
}
No error tipps shows on IDEA when coding, but error shows in compile:
Method bar in class Foo has illegal modifiers: 0x19
java.lang.ClassFormatError: Method bar in class Foo has illegal modifiers: 0x19
Problem is solved, this is a bug and fixed in 1.4.20

It's a bug in compiler. Will be fixed in 1.4.20.

According to https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html:
Default methods are available only for targets JVM 1.8 and above.

Related

Instantiating classes from non-reified type parameters

I'm building an ORM for use with jasync-sql in Kotlin and there's a fundamental problem that I can't solve. I think it boils down to:
How can one instantiate an instance of a class of type T, given a
non-reified type parameter T?
The well known Spring Data project manages this and you can see it in their CrudRepository<T, ID> interface that is parameterised with a type parameter T and exposes methods that return instances of type T. I've had a look through the source without much success but somewhere it must be able to instantiate a class of type T at runtime, despite the fact that T is being erased.
When I look at my own AbstractRepository<T> abstract class, I can't work out how to get a reference to the constructor of T as it requires accessing T::class.constructors which understandably fails unless T is a reified type. Given that one can only used reified types in the parameters of inline functions, I'm a bit lost as to how this can work?
On the JVM, runtime types of objects are erased, but generic types on classes aren't. So if you're working with concrete specializations, you can use reflection to retrieve the type parameter:
import java.lang.reflect.*
​
abstract class AbstractRepository<T>
​
#Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
generateSequence<Type>(this) {
(it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
?.genericSuperclass
}
.filterIsInstance<ParameterizedType>()
.first { it.rawType == AbstractRepository::class.java }
.actualTypeArguments
.single() as Class<T>
​
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
​
fun main() {
println(IntRepository::class.java.repositoryType())
println(StringRepository::class.java.repositoryType())
println(FooRepository::class.java.repositoryType())
println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar
In your own CrudRepository you can add a companion object with an inline fun which is responsible to instantiate your repository by passing to it the corresponding class.
class MyCrudRepository<T> protected constructor(
private val type: Class<T>,
) {
companion object {
inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
}
fun createTypeInstance() = type::class.createInstance()
}

Kotlin deprecated companion instance

When creating a private companion object in Kotlin, why is the Companion static variable marked as #Deprecated public in the bytecode? Is that just a workaround to "simulate" a private behaviour discouraging developers from using that field (since a public companion object doesn't get marked as deprecated)?
Example:
Kotlin
class MyClassWithCompanion {
private companion object {
private val FOO = "FOO"
}
}
Bytecode
// DEPRECATED
// access flags 0x20019
public final static LMyClassWithCompanion$Companion; Companion
#Ljava/lang/Deprecated;()
The #Deprecated annotation is placed as an intermediate solution to avoid breaking binary compatibility when a compiler bug was fixed. The field wasn't supposed to be generated as public when the companion object is private, but due to an oversight it was. In Kotlin 1.4, it will be marked as private.
See this issue for more information.

Getting class of lateinit property in Kotlin

Is it somehow possible to get ::class.java from Kotlin lateinit property before it is initialized?
Logically it should work - I'm trying to obtain a class not a value, but in reality it fails with uninitialized property access exception.
Note that the property I'm trying to get class of is in generic class and its type is one of generic parameters:
abstract class MVIFragment<
out INTERACTOR : MVIInteractor<UINTERFACE>,
UINTERFACE : MVIUIInterface,
MODEL : MVIViewModel
>
: Fragment(), MVIUIInterface, KodeinAware {
lateinit var viewModel: MODEL
I need the class to create an instance of ViewModel
viewModel = ViewModelProviders.of(this).get(viewModel::class.java)
Of course I can't do:
viewModel = ViewModelProviders.of(this).get(MODEL::class.java)
Any solution for that?
Due to type erasure, generic types are not known at runtime. That's just how Java/JVM works, and Kotlin doesn't attempt to magically work around it. (Unlike Scala, which has implicit magic which works magically, except when it doesn't.)
You will have to pass it along from some context where the type is statically determined, e.g.
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
}
Container(String::class.java)
You can use an inline function with reified types to hide this ugliness,
class Container<T : Any>(private val tClass: Class<T>) {
val t: T = tClass.newInstance()
companion object {
inline operator fun <reified T : Any> invoke() = Container(T::class.java)
}
}
Container<String>()
which really compiles to the same thing. (The <String> can be omitted if type inference can determine it from context.)
In your case, it won't be possible to do this trick in the base (abstract) class; it has to be done on the concrete types.

Strange "Val cannot be reassigned" error when setting a property in Kotlin of a Java object

The strange thing is that my Kotlin code compiled fine before, when it looked like this in the java class Allocator:
public void setAllocMethod(#NotNull AllocMethod allocMethod) {
this.allocMethod = allocMethod;
}
but when I changed the java class' setter to this:
public void setAllocMethod(#Nullable AllocMethod allocMethod) {
this.allocMethod= allocMethod;
}
then when I compile the project, I get this Kotlin error in the kt file that calls the java object:
Val Cannot be Reassigned
allocator.allocMethod = DefaultAllocMethod() // kotlin code
also here is the java getter:
public #NotNull AllocMethod getAllocMethod() {
if (allocMethod == null) allocMethod = DefaultAllocMethod.newDefault();
return allocMethod;
}
DefaultAllocMethod is a java subclass of AllocMethod
allocator is of type Allocator, which is a java class that has the getter and setter described above.
Can anyone explain what is happening? thanks
Your setters's type #Nullable AllocMethod, which is Kotlin's AllocMethod?, does not match the getters type #NotNull AllocMethod, which is Kotlin's AllocMethod
What the error message means is that since the types do not match, only the getter is considered as a property. So from the Kotlin's point of view instead of a var allocMethod you have val allocMethod and fun setAllocMethod(...)
Remember that an AllocMethod? is an Any? and that an AllocMethod is an Any. That helps to understand why these getters and setters don't match up.

Unable to reference companion object methods

I have the following code:
fun process(call: () -> Int) {
}
fun aa() = 5
class A {
companion object Factory {
fun bb() = 6
}
}
fun test() {
process(::aa) // OK
process(::A.bb) // Overload resolution ambiguity
}
When I try to call process(::A.bb) I get the following error:
Error:Overload resolution ambiguity:
public constructor A() defined in ru.netimen.hitch_hikingstats.A
public companion object Factory defined in ru.netimen.hitch_hikingstats.A
Is there any way to reference companion object methods?
In Kotlin 1.4+ you can use process(A::bb).
In 1.1.2+ you can use process(A.Factory::bb) or process((A)::bb).
Not so long after this question was asked Kotlin 1.1 was released with support for bound callable references:
https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md#11-m01-eap-1
https://blog.jetbrains.com/kotlin/2016/07/first-glimpse-of-kotlin-1-1-coroutines-type-aliases-and-more/
http://kotlinlang.org/docs/reference/whatsnew11.html#bound-callable-references
http://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11
Kotlin 1.1.2 came with a fix for KT-15951, meaning that since then you can call process(A.Factory::bb).
There is also KT-13934 targeted for Kotlin 1.4, to support process(A::bb).
Syntactically it would be A.Factory:bb but it will not work. At first, bb is a A.Factory.() -> Int while () -> Int is required.
Secondly, callable references to object members are not supported at the moment as the Kotlin compiler says. Here's a parent task for all callable members tasks: https://youtrack.jetbrains.com/issue/KT-1183.