I could not call java static function even after referring to Possibility to call a Java static method in Kotlin
I am new to Kotlin and Java, and i made a WearOS test code in kotlin.
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
....
class SensorActivity: Activity() {
private var mSensor: Sensor? = null // import success
....
fun myCode() {
// i could not use getMaxLengthValuesArray
val num = Sensor.getMaxLengthValuesArray(mSensor, sdkLevel);
}
}
The getMaxLengthValuesArray is method of Sensor class which is declared in public
and the method is also public static.
So i think i can access Sensor.getMaxLengthValuesArray according to the above ref Possibility to call a Java static method in Kotlin, but it does not work.
Is there something wrong with my understanding of Kotlin syntax?
I'm writing Kotlin alongside java in an Android project, I have an abstract Java BaseApplication class which has some static methods, and my Application classes for each flavors extends this BaseApplication class (called App.kt) and are written in Kotlin. I wonder why I cant access BaseApplication static functions through App class in Kotlin code
public abstract class BaseApplication extends Application {
public static void staticFunction(){
Log.d("TAG", "some log...");
}
}
public class App : BaseApplication() {
fun doSomething(){
Log.w("TAG", "doing something")
}
I can call App.staticFunction() from a Java class but I cant call it from a Kotlin class. Am I doing something wrong? Why I can't call App.staticFunction() ? What is the difference?
I can do this from java:
public class JavaTest {
public void main(String[] args) {
App.staticFunction();
}
}
But this(kotlin) gives me compile error:
class KotlinTest {
fun main(args: Array<String>) {
App.staticFunction() //unresolved reference: static function
}
}
(I know I can access staticFunction through AbstractApplication, I just want to know why I cant access it through App class?)
From the Kotlin documentation on Java interop:
Static members of Java classes form "companion objects" for these
classes. We cannot pass such a "companion object" around as a value,
but can access the members explicitly ...
Your App class is a Kotlin class and doesn't know anything about the static method. However there should be a companion object that has been created for the static Method on the BaseApplication Java class. So you should be able to call the static method with
BaseApplication.staticFunction()
you can use easily
public class App : BaseApplication() {
fun doSomething(){
Log.w("TAG", "doing something")
BaseApplication.staticFunction()
}
override fun onCreate() {
super.onCreate()
staticFunction() // you can call without problem
}
}
I have a Scala Implicit class from RecordService API, which i wanted to use in Java file.
package object spark {
implicit class RecordServiceContext(ctx: SparkContext) {
def recordServiceTextFile(path: String) : RDD[String] = {
new RecordServiceRDD(ctx).setPath(path)
.map(v => v(0).asInstanceOf[Text].toString)
}
}
}
Now i am trying to import this in a Java file using below import.
import com.cloudera.recordservice.spark.*;
But i am not able to use recordServiceTextFile("path") from sparkContext.
In Scala the import is little different and its working.
Here is simple definition of implicit class in package object
package object spark {
implicit class Ext(param: Int) {
def a = param + 1
}
}
and here is how you can use it from java
public class Test {
public static void main(String[] args) {
spark.package$.MODULE$.Ext(123).a();
}
}
so you can basically use RecordServiceContext as a method that wraps your SparkContext and adds an extra method that you can call. That is optimization for implicit classes.
That would be something like this:
SparkContext c = ???
RDD<String> rdd = com.cloudera.recordservice.spark.package$.MODULE$.RecordServiceContext(c)
.recordServiceTextFile("asdf");
A package object spark is compiled to a class package in the package spark. The implicit class RecordServiceContext will get compiled to a static method RecordServiceContext (that's scala's implicit def) in package and a class package$RecordServiceContext.
So the following code should do it:
import com.cloudera.recordservice.spark.*;
//some code
RDD<String> rdd = package.RecordServiceContext(myContext).recordServiceTextFile(pathToFile);
//some code
But package is probably a reserved keyword, and Java has no way of escaping them as far as I know. So you'll have to do some reflection to invoke the RecordServiceContext method.
SparkContext ctx = ...
RecordServiceContext rsct = new RecordServiceContext(ctx)
recordServiceTextFile("/your_path")
This should do it.
String s = new spark.RecordServiceContext("safa").recordServiceTextFile("dsf");
I changed the signatures though.
My Scala class looks like this ,
object spark {
implicit class RecordServiceContext(ctx: String) {
def recordServiceTextFile(path: String) : String = {
"test"
}
}
}
My java class looks like this,
public class TestScalaCall {
public static void main(String args[]){
String s = new spark.RecordServiceContext("safa").recordServiceTextFile("dsf");
}
}
Edit ---
So a quick look of the Scala change requests shows us this.
They are actually working on making a class defined under a package object behave the same way as defining it inside a regular package. But that is targeted for the yet to be release 2.12 .
So the recommendation they are giving is keep only absolutely necessary classes/objects that do not needs any external interaction inside package objects. Otherwise keep them under regular packages.
So for now you need to not use the package object construct.
Also , a point worth pondering "Does it really make sense to define something that is accessible on the outside inside a package object ? "
Is it possible to access extension functions from Java code?
I defined the extension function in a Kotlin file.
package com.test.extensions
import com.test.model.MyModel
/**
*
*/
public fun MyModel.bar(): Int {
return this.name.length()
}
Where MyModel is a (generated) java class.
Now, I wanted to access it in my normal java code:
MyModel model = new MyModel();
model.bar();
However, that doesn't work. The IDE won't recognize the bar() method and compilation fails.
What does work is using with a static function from kotlin:
public fun bar(): Int {
return 2*2
}
by using import com.test.extensions.ExtensionsPackage so my IDE seems to be configured correctly.
I searched through the whole Java-interop file from the kotlin docs and also googled a lot, but I couldn't find it.
What am I doing wrong? Is this even possible?
All Kotlin functions declared in a file will be compiled by default to static methods in a class within the same package and with a name derived from the Kotlin source file (First letter capitalized and ".kt" extension replaced with the "Kt" suffix). Methods generated for extension functions will have an additional first parameter with the extension function receiver type.
Applying it to the original question, Java compiler will see Kotlin source file with the name example.kt
package com.test.extensions
public fun MyModel.bar(): Int { /* actual code */ }
as if the following Java class was declared
package com.test.extensions
class ExampleKt {
public static int bar(MyModel receiver) { /* actual code */ }
}
As nothing happens with the extended class from the Java point of view, you can't just use dot-syntax to access such methods. But they are still callable as normal Java static methods:
import com.test.extensions.ExampleKt;
MyModel model = new MyModel();
ExampleKt.bar(model);
Static import can be used for ExampleKt class:
import static com.test.extensions.ExampleKt.*;
MyModel model = new MyModel();
bar(model);
Kotlin top-level extension function are compiled as Java static methods.
Given Kotlin file Extensions.kt in package foo.bar containing:
fun String.bar(): Int {
...
}
The equivalent Java code would be:
package foo.bar;
class ExtensionsKt {
public static int bar(String receiver) {
...
}
}
Unless, that is, Extensions.kt contained the line
#file:JvmName("DemoUtils")
In which case the Java static class would be named DemoUtils
In Kotlin, extension methods can be declared in other ways. (For example, as a member function or as an extension of a companion object.)
With newer KotlinEx, you can directly call extension in java
ExtensionFileName.foo(field1...)
Basically, what it does is, it makes the receiver as first arguement and other arguments remain being at the same place
So For eg.
You have extension(in file Extension.kt)
Context.showToast(message:String){
...
}
In Java, you call it as
ExtensionKt.showToast(context, message);
I have a Kotlin file called NumberFormatting.kt that has the following function
fun Double.formattedFuelAmountString(): String? {
val format = NumberFormat.getNumberInstance()
format.minimumFractionDigits = 2
format.maximumFractionDigits = 2
val string = format.format(this)
return string
}
In java I simple access it over the file NumberFormattingKt in the following way after the required import import ....extensions.NumberFormattingKt;
String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());
You can always see the actual Java code which is getting generated from your Kotlin code by going to Tools > Kotlin > Show Kotlin Bytecode, then clicking Decompile. This can help you tremendously. In your case the Java code will look like this if you have MyModelExtensions.kt
public final class MyModelExtensionsKt {
public static final int bar(#NotNull MyModel $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getName().length();
}
}
you can improve over this by using #JvmName on the file containing bar:
#file:JvmName("MyModels")
package io.sspinc.datahub.transformation
public fun MyModel.bar(): Int {
return this.name.length
}
and it will result in this code:
public final class MyModels {
public static final int bar(#NotNull MyModel $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getName().length();
}
}
Using MyModels is in line with what Effective Java suggests for utility classes. You can also rename your method like this:
public fun MyModel.extractBar(): Int {
return this.name.length
}
then from the Java side it will look idiomatic:
MyModels.extractBar(model);
It works for me:
Kotlin
Java code
My project is an old android project created with Java; now I created the first kotlin file and added String extensions
fun String.isNotNullOrEmpty(): Boolean {... }
and I could call it from java file using:
StringUtilsKt.isNotNullOrEmpty(thestring).
My kotlin file name is StringUtils
The other answers here cover the case of calling an extension function located at the top level of a Kotlin package file.
However, my case was that I needed to call an Extension function located inside a Class. Specifically, I was dealing with an Object.
The solution is incredibly simple.
All you have to do is annotate your extension function as #JvmStatic, and voila! Your Java code will be able to access it and use it.
When you extend a class like this:
fun String.concatenatedLength(str: String): Int {
return (this.length + str.length)
}
fun f() {
var len = "one string".concatenatedLength("another string")
println(len)
}
It will compile to this:
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
public final class ExampleKt {
public static final int concatenatedLength(#NotNull String $receiver, #NotNull String str) {
Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver");
Intrinsics.checkParameterIsNotNull((Object) str, (String) "str");
return $receiver.length() + str.length();
}
public static final void f() {
int len = ExampleKt.concatenatedLength("one string", "another string");
System.out.println(len);
}
}
There are more examples here.
As far as I can tell this isn't possible. From my reading of the extensions docs, it appears that
public fun MyModel.bar(): Int {
return this.name.length()
}
creates a new method with the signature
public static int MyModelBar(MyModel obj) {
return obj.name.length();
}
Then, Kotlin maps that function to calls of the form myModel.bar(), where if bar() isn't found in the MyModel class it looks for static methods matching the signature and naming scheme it outputs. Note that this is just an assumption from their statements about extensions being statically imported and not overriding defined methods. I haven't gotten far enough in their source to know for sure.
So, assuming the above is true there's no way for Kotlin extensions to be called from plain old java code, as the compiler will just see an unknown method being called on an object and error out.
Considering a java application with a embedded X impl/jar file, for example com.test package.
and we cannot change and modify the jar file.
Now suppose I have a X1.jar file which is modified version of exist X(com.test) package.
Question:
Is it possible to override the X1.jar implementation with embedded(exist) implementation just before the library gets loaded? and again, assume we cannot change the package anyway.
I'd like that to redirect all the types under com.test package to the new one.
Thanks in advance.
As per m0skit0's suggestion:
Orig class:
package example.x
public class SomeClass
{
public SomeClass(String neededVar)
{...}
public String someMethod(String someVar)
{
// original implementation
}
}
Custom class:
import example.x.SomeClass
public class MySomeClass extends SomeClass
{
public MySomeClass(String neededVar)
{
super(neededVar);
// anything else
}
#Override
public String someMethod(String someVar)
{
// implement differently
super.someMethod(someVar);
// or add to it
}
}