Native access Java fields

  • KotlinFields.kt
package com.practice

var topLevelField = "top"

class KotlinFields {

  var number: Int = 3

  companion object {
    @JvmField
    var companionField: Double = 9.0
  }

}

Call Kotlin from Java @Kotlin Programming Language

Check the signature after compile it.

$ ls
KotlinFields$Companion.class  KotlinFields.class            KotlinFieldsKt.class          Lib.class                     MainActivity.class
$ javap -p -s com/practice/KotlinFieldsKt.class 
Compiled from "KotlinFields.kt"
public final class com.practice.KotlinFieldsKt {
  private static java.lang.String topLevelField;
    descriptor: Ljava/lang/String;
  public static final java.lang.String getTopLevelField();
    descriptor: ()Ljava/lang/String;

  public static final void setTopLevelField(java.lang.String);
    descriptor: (Ljava/lang/String;)V

  static {};
    descriptor: ()V
}

$ javap -p -s com/practice/KotlinFields\$Companion.class 
Compiled from "KotlinFields.kt"
public final class com.practice.KotlinFields$Companion {
  private com.practice.KotlinFields$Companion();
    descriptor: ()V

  public com.practice.KotlinFields$Companion(kotlin.jvm.internal.DefaultConstructorMarker);
    descriptor: (Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

$ javap -p -s com/practice/KotlinFields.class 
Compiled from "KotlinFields.kt"
public final class com.practice.KotlinFields {
  private int number;
    descriptor: I
  public static double companionField;
    descriptor: D
  public static final com.practice.KotlinFields$Companion Companion;
    descriptor: Lcom/practice/KotlinFields$Companion;
  public final int getNumber();
    descriptor: ()I

  public final void setNumber(int);
    descriptor: (I)V

  public com.practice.KotlinFields();
    descriptor: ()V

  static {};
    descriptor: ()V
}
  • MainActivity.kt
package com.practice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    topLevelField = "top-java"
    KotlinFields.companionField = 3.0

    val fields = KotlinFields()
    fields.number = 5

    Lib().callNative(fields)

    println("top level field is $topLevelField")
    println("companion field is ${KotlinFields.companionField}")
    println("member is ${fields.number}")
  }

}
  • native-lib.cpp
#include <jni.h>
#include <android/log.h>

constexpr const char *TAG = "nativeCode";

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

constexpr const char *TOP_LEVEL_CLASS_NAME = "com/practice/KotlinFieldsKt";
constexpr const char *TOP_LEVEL_FIELD_NAME = "topLevelField";

constexpr const char *CLASS_NAME = "com/practice/KotlinFields";
constexpr const char *MEMBER_NAME = "number";
constexpr const char *COMPANION_FIELD_NAME = "companionField";

constexpr const char *TYPE_STR = "Ljava/lang/String;";
constexpr const char *TYPE_INT = "I";

jclass getClass(JNIEnv *env, const char *path) {
  jclass cls = env->FindClass(path);
  if (cls == nullptr) {
    LOGE("cls %s not found.", path);
  }
  return cls;
}

jfieldID getStaticFieldId(JNIEnv *env, jclass cls, const char *methodName, const char *sig) {
  jfieldID result = env->GetStaticFieldID(cls, methodName, sig);
  if (result == nullptr) {
    LOGE("static field id for %s(%s) not found.", methodName, sig);
  }
  return result;
}

jstring getTopLevelField(JNIEnv *env) {
  jclass cls = getClass(env, TOP_LEVEL_CLASS_NAME);
  jfieldID fieldId = getStaticFieldId(env, cls, TOP_LEVEL_FIELD_NAME, TYPE_STR);
  auto result = (jstring) env->GetStaticObjectField(cls, fieldId);
  env->DeleteLocalRef(cls);
  return result;
}

void setTopLevelField(JNIEnv *env, const char *text) {
  jclass cls = getClass(env, TOP_LEVEL_CLASS_NAME);
  jfieldID fieldId = getStaticFieldId(env, cls, TOP_LEVEL_FIELD_NAME, TYPE_STR);
  jstring javaText = env->NewStringUTF(text);
  env->SetStaticObjectField(cls, fieldId, javaText);
  env->DeleteLocalRef(javaText);
  env->DeleteLocalRef(cls);
}

jdouble getCompanionField(JNIEnv *env) {
  jclass cls = getClass(env, CLASS_NAME);
  jfieldID fieldId = getStaticFieldId(env, cls, COMPANION_FIELD_NAME, "D");
  auto result = env->GetStaticDoubleField(cls, fieldId);
  env->DeleteLocalRef(cls);
  return result;
}

void setCompanionField(JNIEnv *env, jdouble value) {
  jclass cls = getClass(env, CLASS_NAME);
  jfieldID fieldId = getStaticFieldId(env, cls, COMPANION_FIELD_NAME, "D");
  env->SetStaticDoubleField(cls, fieldId, value);
  env->DeleteLocalRef(cls);
}

jint getMember(JNIEnv *env, jobject obj) {
  jclass cls = env->GetObjectClass(obj);
  jfieldID fieldId = env->GetFieldID(cls, MEMBER_NAME, TYPE_INT);
  jint result = env->GetIntField(obj, fieldId);
  env->DeleteLocalRef(cls);
  return result;
}

void setMember(JNIEnv *env, jobject obj, jint value) {
  jclass cls = env->GetObjectClass(obj);
  jfieldID fieldId = env->GetFieldID(cls, MEMBER_NAME, TYPE_INT);
  env->SetIntField(obj, fieldId, value);
  env->DeleteLocalRef(cls);
}

extern "C" JNIEXPORT void JNICALL
Java_com_practice_Lib_callNative(JNIEnv *env, jobject /* this */, jobject obj) {
  // get top level field
  jstring topStaticField = getTopLevelField(env);
  const char *topStaticFieldNative = env->GetStringUTFChars(topStaticField, JNI_FALSE);
  LOGD("top static field is %s", topStaticFieldNative);
  env->ReleaseStringUTFChars(topStaticField, topStaticFieldNative);
  env->DeleteLocalRef(topStaticField);

  // set top level field
  setTopLevelField(env, "native top level value");

  // get companion field
  jdouble companionField = getCompanionField(env);
  LOGD("companion field is %lf", companionField);

  // set companion field
  setCompanionField(env, 98.7);

  // get member
  LOGD("member is %d", getMember(env, obj));

  // set member
  setMember(env, obj, 789);
}
  • LogCat
D/nativeCode: top static field is top-java
D/nativeCode: companion field is 3.000000
D/nativeCode: member is 5

I/System.out: top level field is native top level value
I/System.out: companion field is 98.7
I/System.out: member is 789

results matching ""

    No results matching ""