How to call java static function in kotlin - java

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?

Related

Kotlin top level function with private java contructor

I have the kotlin file with top level function and specified name for using it from java code:
Utility.kt
#file:JvmName("Utility")
package com.example
fun someUtilityFunc() {
// ignored
}
and I can instantiate Utility class in my Java code:
Main.java
package com.example;
public Main {
public static void main(String[] args) {
new Utility();
}
}
How can I add the private constructor to generated Utility class?
You can't. file:JvmName will generate a regular class with static methods.
If you absolutely don't want to have this constructor, you'll have to use object
object Utility {
fun someUtilityFunc() {
// ignored
}
}
Now previously, you could just called someUtilityFunc() in your Kotlin code, and it just worked.
But thankfully you can import functions in Kotlin, so it still works without prefixing:
import com.example.Utility.someUtilityFunc
fun main() {
someUtilityFunc()
}

How to import Java static method into Drools file?

The java class and static method code is:
public class DroolsStringUtils {
public static boolean isEmpty(String param) {
if (param == null || "".equals(param)) {
return true;
}
return false;
}
}
The drl code is:
package com.rules
import com.secbro.drools.utils.DroolsStringUtils.isEmpty;
rule CheckIsEmpty
when
isEmpty("");
then
System.out.println("the param is not empty");
end
But the IDEA hints:
"cannot relove" on the method 'isEmpty("")'.
I just want to import a static method from java class to drl file.
Use import static to import a static method.
import static com.secbro.drools.utils.DroolsStringUtils.isEmpty;
// ^^^^^^
(edited:) and of course you cannot call a static method where a pattern is required:
rule CheckIsEmpty
when
eval( isEmpty("") )
then
System.out.println("the param is not empty");
end
(It helps considerably to read the Drools documentation.)
[this might have details only relevant for Drools 6.0 & earlier (thanks Roddy of the Frozen Peas)]
Looks like you could import the static method, as a function into Drools...
import function com.secbro.drools.utils.DroolsStringUtils.isEmpty
...and then be able to use your rule as you wrote it originally in your Question.
It seems [classic Java-style] static imports are not supported in
Drools
But it seems they can be imported with Drools function import
style
FWIW: To reference static fields - import the class with the static fields as normal import (not static or function), and then refer to static field with static reference:
import your.package.with.static.field.YourClass
...
YourClass.STATIC_FIELD
(That also works for static methods too, if you don't want to import them as function).

How to capture incoming parameters with EasyMock.capture?

I'm testing a class and wanted to monitor calls to a specific method, namely to save the calling parameters for later analysis.
Testing is done with EasyMock, so it was logical to use EasyMock.capture feature. However, the examples that I managed to find do not work for me - I get the following compile error at the line with capture:
expect(T) in EasyMock cannot be applied to (void)
reason: no instance of type variable T exist so that void conforms to T
It would be great if somebody could point out my mistake(s) for me. Below is a code snippet:
import static org.easymock.EasyMock.capture;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
class B {
}
class A {
public void doSomething(B input) {
}
}
public class ATest {
private Capture<B> capturedData;
private A testObject;
#Before
private void setUp() {
capturedData = EasyMock.newCapture(CaptureType.ALL);
testObject = EasyMock.createNiceMock(A.class);
EasyMock
.expect(testObject.doSomething(capture(capturedData)))
.anyTimes();
}
}
Thanks a lot in advance!
Your problem is not related to the capture, but to the return type of your doSomething() method:
Since A.doSomething(B input) is of return type void, you don't expect the method to return anything, thus you cannot use EasyMock.expect() for it. Instead, simply invoke the method and use EasyMock.expectLastCall(), like so:
testObject.doSomething(capture(capturedData));
EasyMock.expectLastCall().anyTimes();
EasyMock.expectLastCall() declares that you expect the last method invocation before expectLastCall() to be executed. You can then handle it just like expect(), e.g. add anyTimes() to it.

How to use Scala implicit class in Java

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 ? "

Accessing Kotlin extension functions from Java

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.

Categories