Static methods in Kotlin as static method in Java - kotlin

I am trying to create a static method in Kotlin, that allows proper inter-op with Java.
Context: I want to pass a java.lang.reflect.Method reference to org.springframework.expression.spel.support.StandardEvaluationContext#registerFunction so add custom functionality to Spring's expression Language.
I created a companion object:
companion object {
#JvmStatic
fun foo(): Boolean = true
}
And get the reference via
Companion::foo.javaMethod!!
or
Companion.javaClass.getMethod("foo").modifiers
However, when I call Modifier.isStatic on the result, it returns false and when I try to evaluate an expression with the registered function, I also get
org.springframework.expression.spel.SpelEvaluationException:
EL1039E: Only static methods can be called via function references.
The method '…$Companion.foo' referred to by name 'foo' is not static.
How can I fix that?

Works for me this way:
class C {
companion object {
#JvmStatic
fun foo(): Boolean = true
}
}
val method = C::class.java.getDeclaredMethod("foo")
Modifier.isStatic(method.modifiers) // true
Note that C::class.java and C.javaClass are different things: the former returns Class<C> and the latter returns Class<C.Companion>.

Related

Can I add Kotlin extension function to Java class?

I'm trying to create extension function like this:
fun UHFTAGInfo.toReadUhfTagInfo(): ReadUhfTagInfo {
return ReadUhfTagInfo(this.epc, this.count, this.rssi.toIntOrNull())
}
It is supposed to convert UHFTAGInfo (from java library) to ReadUhfTagInfo (my class in Kotlin).
I'm trying to use it like this:
UHFTAGInfo i = getUHFTAGInfo();
ReadUhfTagInfo ri = i.toReadUhfTagInfo();
At this moment my toReadUhfTagInfo function is at top level, but finally I want to put it in my ReadUhfTagInfo class, like this:
class ReadUhfTagInfo(var epc: String, var cnt: Int, var rssi: Int?)
{
fun UHFTAGInfo.toReadUhfTagInfo(): ReadUhfTagInfo {
return ReadUhfTagInfo(this.epc, this.count, this.rssi.toIntOrNull())
}
}
You can call Kotlin extension functions from Java, sure, but you can't call them with extension function syntax, you must call them like static methods. If you, for example, define
// file: Foo.kt
fun Bar.baz() { ... }
then in Java, you would call this as
FooKt.baz(bar);
I don't think you want to have toReadUhfTagInfo as a member function on the ReadUhfTagInfo class. That would imply that, in order to convert a UHFTAGInfo to a ReadUhfTagInfo, you already need a ReadUhfTagInfo object (which will presumably go unused except to serve as the receiver object.
Extension functions defined inside a class are member extensions and essentially have two receivers.
You can declare extensions for one class inside another class. Inside such an extension, there are multiple implicit receivers - objects whose members can be accessed without a qualifier. An instance of a class in which the extension is declared is called a dispatch receiver, and an instance of the receiver type of the extension method is called an extension receiver.
If you want the extension method to act like a static method in Java (i.e. not require an instance of the enclosing class to execute), then you do the same thing we do with all static methods in Kotlin: We put it in a companion object.
class ReadUhfTagInfo(var epc: String, var cnt: Int, var rssi: Int?)
{
companion object {
fun UHFTAGInfo.toReadUhfTagInfo(): ReadUhfTagInfo {
return ReadUhfTagInfo(this.epc, this.count, this.rssi.toIntOrNull())
}
}
}
As pointed out in the comments, this will still require the name to be imported into the current scope (as all extension methods do), but it won't require a receiver of type ReadUhfTagInfo to call anymore.

How to understand Kotlin Functional Interface with companion object inside?

I would like to get some help to understand a Kotlin code snippet about functional interface used in Http4k org.http4k.core package
typealias HttpHandler = (Request) -> Response
fun interface Filter : (HttpHandler) -> HttpHandler {
companion object
}
I don’t understand the Filter interface, especially the companion object part. A typical functional interface is like this
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
And you can create a lambda isEven
val isEven = IntPredicate { it % 2 == 0 }
According to this simple example, it looks like the interface Filter extends another interface (HttpHandler) -> HttpHandler? Then it defines a function signature companion object? Is this correct? What does the part companion object really mean?
Filter extends (HttpHandler) -> HttpHandler and the function type (HttpHandler) -> HttpHandler has a single abstract method (operator) - invoke - implicitly declared, like this:
operator fun invoke(HttpHandler): HttpHandler
So that is the function signature for the functional interface, not companion object.
companion object means what it has always meant - a companion object declaration. The companion object might seem empty, just from looking at the code you showed, and it makes one wonder what its purpose is. If you have removed the declaration, the functional interface would still have compiled, and can be used just like a functional interface representing the function type (HttpHandler) -> HttpHandler.
If you look further down the file, however, you'll see that there is (at least) one extension function declared on the companion object:
val Filter.Companion.NoOp: Filter get() = Filter { next -> { next(it) } }
This allows you to do val noOp = Filter.NoOp for example, so the companion object isn't that pointless.

How to define an extension function for a companion object of a typealias?

I thought typealiases were the same as the original type, just a different name.
I figure typealiases have the same references as the original type.
typealias Celsius = Double
fun Double.Companion.foo() {} // Works
fun Celsius.Companion.foo() {} // Does not work
Here, Companion is accessible from Double but Celsius gives an unresolved reference error.
No, you can't access to the companion objects via typealias. One possible workaround to create one more typealias for concrete companion:
typealias CelsiusCompanion = Double.Companion
After that you can use it as following:
fun CelsiusCompanion.foo() {}
If you want to define an extension function, it is not possible as hluhovskyi already stated, but things are differently if you just want to invoke functions of a companion object.
There are two ways of accessing functions and properties within a companion object. You can either specify the access explicitely or implicitely. The implicit way works with a typealias the explicit one does not.
Consider this minimal example:
class ClassWithCompanion{
companion object {
fun sayHello() {
println("Hello")
}
}
}
typealias Alias = ClassWithCompanion
fun main(args: Array<String>) {
ClassWithCompanion.sayHello() // implicit
ClassWithCompanion.Companion.sayHello() // explicit
Alias.sayHello() // implicit (works)
Alias.Companion.test() // explicit (does not work)
}

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

How to write a package-level static initializer in Kotlin?

A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}