Kotlin object private when accessed from Java - java

I have some Kotlin code like this
object NativeInterface {
// Used to load the 'native-lib' library on application startup.
public val effectDescriptionMap: Map<String, EffectDescription>
and I'm trying to access from Java like this:
Effect it = NativeInterface.effectDescriptionMap[menuItem.title];
But it keeps saying that effectDescriptionMap is private, even though I explicitly placed public on it. From Kotlin I can access but not from Java.

The NativeInterface is an object not a class. You have to access the INSTANCE
NativeInterface.INSTANCE.getEffectDescriptionMap()

Related

creating "public" constants in a kotlin class [duplicate]

This question already has answers here:
What is the equivalent of Java static final fields in Kotlin?
(4 answers)
Closed 2 years ago.
Perhaps it was bad practice but in Java I would often create something like:
public class MyService extends Service {
public static final String ACTION_CONNECTED = "blablabla";
...
}
And reference it in another class like:
MyService.ACTION_CONNECTED
This was great. I could keep my constants nicely associated with their class.
I can't seem to find an equivalent in Kotlin. I see solutions flying around suggesting people create constants files (objects) but I don't think that's very elegant. I want there to be some way to expose a top-level const val BLAB outside its file so I can keep my ClassName.CONSTANT syntax going but it doesn't look like it's in the cards.
Is there (and what is it) a Kotlin equilivant to the good old public static final with regard to sharing constants between classes?
class MyService {
companion object {
#JvmStatic const val ACTION_CONNECTED = "blablabla"
}
}
MyService.ACTION_CONNECTED
This will be the equivalent of public static final for kotlin
If you want to create a final variable in kotlin, use val instead of using var
val LastCount = 1
and for creating a static variable use companion object key
companion object{
val lastCount = 1
}
now you want to have access to this variable in other classes.
so create a new class like this:
class Counter{
companion object{
val lastCount = 1
}
}
and then use it all over the project like this
Counter.lastCount
According to Jetbrains in this video:
https://www.coursera.org/learn/kotlin-for-java-developers/lecture/85GKr/objects-object-expressions-companion-objects
There are 3 ways to create static methods or functions for a class:
Declare static members at the top level (Default approach)
Declare them inside objects (Singletons)
Declare them inside companion objects
Using method 1 should be the easiest approach for you if you want to mimic the experience in Java as close as possible. You will be able to access the members using either the getter under the hood or using direct access. Here's an example:
MyService.kt will be the name of your Kotlin file.
val ACTION_CONNECTED = "blablabla"
class MyService :Service{
//your other class details
}
You can access it like this from another Kotlin file or Activity:
val myAction=ACTION_CONNECTED
It would also be better if you mark it as const, since it is a constant value like this:
const val ACTION_CONNECTED = "blablabla"

Hiding Kotlin object's INSTANCE field from Java (and Kotlin)

Short question
Can I modify the visibility of a Kotlin object's INSTANCE (for Java interop) to internal or lower?
Long question
I'm writing a library and I want to have an API file / class, written in Kotlin, that exposes a function to be called from either Java or Kotlin like this:
Kotlin:
API.function()
Java:
API.function();
I can achieve this by writing it like this:
Kotlin:
object API {
#JvmStatic
fun function() = TODO()
}
However, now I can also do this:
Java:
API.INSTANCE.function();
I want to prevent this access to INSTANCE to keep my API surface to a minimum for simplicity.
Can I modify the visibility of INSTANCE to internal or lower?
It's probably not possible, because any call to API (from Kotlin) returns the object's instance and that should probably be hidden too for this to be possible. However, I'm curious to see if it is without major hacks.
A solution using Java would be to write API in Java:
public final class API {
private API() {
}
public static void function() {
}
}
However, I'm looking for a solution written in Kotlin.
The closest I could come up with was something like this:
Create a file API.kt in a package com.example.api. Add your functions directly into that file, like this:
#file:JvmName("API")
package com.example.api
fun function() {
// ...
}
Kotlin:
You can import that function anywhere you need to use your api:
import com.example.api.function
Though you can't use your syntax API.function anymore.
Java:
The generated class would look something like this (no singleton, just static methods, but no private constructor):
public final class API {
public static final void function() {
// ...
}
}
Which then allows you to call it like API.function();
By specifiying #file:JvmName("API") you instruct kotlin to name the created class API.

How is this interface being instantiated?

This is from the Minecraft server source code, also called the Minecraft Bukkit API, now you know as much as I do.
There is an interface called Server:
public interface Server extends PluginMessegeRecipient {
public String getVersion();
}
PluginMessageRecipient is an interface also.
There is a class called Bukkit that instantiates Server:
public final class Bukkit {
private static Server server;
}
Inside methods in the Bucket class they invoke methods from the server object. For example:
server.getVersion();
The thing is, there is no code for getVersion in the Server interface, just a method signature. There is also no code in the PluginMessageRecipient interface nor does it extend anything.
I have read all the questions and answers on SO that say I need an anonymous class or an inner class and this does not seem to fit those solutions.
There is a class called Bucket that instantiates Server:
Actually Bucket doesn't instantiate Server. The class Bucket contains a reference to a Server. You haven't shown how that got set so we don't know the actual class.
However, it is guaranteed that what is assigned to that reference (Bucket.server), assuming it's not null, is a an object of some concrete class that implements Server. That class will provide an implementation of getVersion() and that is what is being called.
Bukkit is just a Modding API. If you want to implement Bukkit, you need to create such an instance yourself and pass it there.
Take for example the unit tests that Bukkit includes:
https://github.com/Bukkit/Bukkit/blob/f210234e59275330f83b994e199c76f6abd41ee7/src/test/java/org/bukkit/TestServer.java#L77
A real implementation that allows you to run a Bukkit server is Spigot.
If I recall correctly, the particular concrete class that's being selected is determined at runtime via reflection. Because Minecraft is not open source, all the developers have are the obfuscated compiled class files to work with.
The code searches through each class file within the minecraft jar, searching for a class that matches certain conditions, and then, using a bytecode library, force that class to implement that interface.
For example, let's say that the following (obfuscated) class was the real Server class within the Minecraft code
class a {
String x_x317() {
return q_q98;
}
static a a_a1;
static String q_q98 = "1.9.4";
}
In this case, the method x_x317 returns the version string. The tool that allows them too hook into this class might do it based on the following conditions:
The class has default access
The class has only one default access static reference to itself
The class has only one default access static String field.
The class has a single method, that has default access, that returns String, and the returned value is the FieldRef found in 3.
This generally returns only one class. In the case that multiple are returned (usually in the dev phase of the new Bukkit version), they get more specific with their conditions to ensure that they only get the right class returned. They do this for every field, class, and method they need to identify.
Since they now know which exact class is the Server class, they can go ahead and make changes to it. First they would need to implement the interface
class a implements org.bukkit.Server
And then implement the method
class a implements org.bukkit.Server {
String x_x317() {
return q_q98;
}
public String getVersionNumber() {
return x_x317();
}
static a a_a1;
static String q_q98 = "1.9.4";
}
Now, we have a class that conforms to the Bukkit API.
When they need to instantiate that class, they just do something along the lines of
Server server = findAndTransformServerClassFromMinecraftJar();
// ...
Server findAndTransformServerClassFromMinecraftJar() {
// load classes from jar
// map them to the appropriate interfaces
// transform and hook the required classes and methods
Class<?> serverClass = doTheFirstThreeSteps();
return (Server) serverClass.newInstance();
}

Is there a way to reference the Java class for a Kotlin top-level function?

I want to load a resource in a top level function using Class.getResourceAsStream().
Is there any way to get a reference to the class that the top level function will be compiled into so that I can write, for example
val myThing = readFromStream(MYCLASS.getResourceAsStream(...))
Another way I found is to declare a local class or an anonymous object inside a top level function and to get its enclosingClass:
val topLevelClass = object{}.javaClass.enclosingClass
Note: to work, this declaration should be placed on top level or inside a top-level function.
Then you can use the topLevelClass as a Class<out Any>:
fun main(args: Array<String>) {
println(topLevelClass) // class MyFileNameKt
}
With Java 7 you can get a reference to the current Java class from a top level function using
MethodHandles.lookup().lookupClass()
No, there is no syntax to reference that class. You can access it using Class.forName(). For example, if the file is called "Hello.kt" and is located in the package "demo", you can obtain the class by calling Class.forName("demo.HelloKt").
In the absence of a way to get a reference directly, I've fallen back on creating an anonymous object in the current package
val myThing = object: Any() {}.javaClass.getResourceAsStream(...)
As linters like detekt would flag anonymous classes as EmptyClassBlock you could also use something like
internal object Resources
fun resourceStream(name: String): InputStream {
return Resources.javaClass.getResourceAsStream(name)
}

Loading a static void C function via AndroidfromJNI another Package

I am trying some things out with JNI and by that I found the following problem:
If I want to use a native function in Java I load the needed lib, in which the needed function is stored, via
static{
System.loadLibrary("lib");
}
and use
native private static int calculate(byte[] numberArray);
to declare the native method in the java file. During the program itself I can use this function to calculate something with:
int result = calculate(array);
This works only if I compiled the shared object with the header-file created by javah so that each function is named on c side as:
static void Java_com_packagename_File_calculate(const void* array, void* result){
code[...]
}
If I delete the reference in the java code ("native [...] calculate[...]")to this c function; is there any possibility to access / execute the still existing c-code via java (of course without editing the exisiting file ;-)) for example via reflections or inheritance? Or is there something possible like:
public class NewClass{
public int nativeCheater(){
System.loadLibrary("lib");
native private static int Java_com_packagename_File_calculate;
}
}
It is important that I want to use a whole new class without any relations to the prior used package com.packagename.(File).
Thanks in advance :-)
No, but you can create a new class with same package and class name and access the same native method. The new class can declare this method public.
An alternative is to use dynamic binding via Jni_OnLoad() and RegisterNatives(). This way, your native implementations may bind to any Java class, or even more than one.
But if you have access neither to the Java class nor to the native source, you can always create your own native method, in your own class, and inside your C explicitly call the original:
static void Java_com_mypackagename_File_calculate(const void* array, void* result) {
Java_com_packagename_File_calculate(array, result);
}

Categories

Resources