X-Git-Url: http://nitlanguage.org diff --git a/lib/java.nit b/lib/java.nit index 9db363c..de82015 100644 --- a/lib/java.nit +++ b/lib/java.nit @@ -15,6 +15,17 @@ # limitations under the License. # Supporting services for the FFI with Java +# +# This modules relies on `Sys::jvm`, `Sys::jni_env` and +# `Sys::create_default_jvm` to get a handle on a JVM. You can adapt the +# behavior of the FFI and services in this module by redefing +# `Sys::create_default_jvm` and supply your own JVM object. You can manage +# multiple java thread by switching the current environment in a redef +# of `Sys::jni_env`, and multiple JVM using `Sys::jvm`. +# +# The module `jvm` gives more control over the JVM instances and wraps +# most of JNI functions. You can use it to further customize the behavior +# of your code. module java is c_compiler_option("-I $(JAVA_HOME)/include/") c_linker_option("-L $(JNI_LIB_PATH) -ljvm") @@ -38,7 +49,6 @@ redef class Sys fun jvm=(jvm: JavaVM) do jvm_cache = jvm # Current main `JniEnv` - # FIXME support threaded Java fun jni_env: JniEnv do if jni_env_cache == null then create_default_jvm @@ -49,7 +59,7 @@ redef class Sys fun jni_env=(jni_env: JniEnv) do jni_env_cache = jni_env # Called by `jvm` and `jni_env` to instanciate a Java Virual Machine. - # Used mostly for FFI with Java. + # Used mostly for the FFI with Java. protected fun create_default_jvm do var builder = new JavaVMBuilder @@ -63,4 +73,94 @@ redef class Sys self.jvm = jvm self.jni_env = builder.jni_env.as(not null) end + + # Get a Java class by its name from the current `jni_env` + fun load_jclass(name: NativeString): JClass import jni_env `{ + JNIEnv *nit_ffi_jni_env = Sys_jni_env(recv); + + // retreive the implementation Java class + jclass java_class = (*nit_ffi_jni_env)->FindClass(nit_ffi_jni_env, name); + if (java_class == NULL) { + fprintf(stderr, "Nit FFI with Java error: failed to load class.\\n"); + (*nit_ffi_jni_env)->ExceptionDescribe(nit_ffi_jni_env); + exit(1); + } + + return java_class; + `} +end + +# A standard Java string `java.lang.String` +# +# Converted to a Nit string using `to_s`, or to a C string with `to_cstring`. +# Created using `String::to_java_string` or `NativeString::to_java_string`. +extern class JavaString in "Java" `{ java.lang.String `} + super JavaObject + + redef type SELF: JavaString + + # Get the string from Java and copy it to Nit memory + fun to_cstring: NativeString import sys, Sys.jni_env `{ + Sys sys = JavaString_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + + // Get the data from Java + const jbyte *java_cstr = (char*)(*env)->GetStringUTFChars(env, recv, NULL); + jsize len = (*env)->GetStringUTFLength(env, recv); + + // Copy it in control of Nit + char *nit_cstr = (char*)malloc(len+1); + memcpy(nit_cstr, java_cstr, len); + nit_cstr[len] = '\0'; + + // Free JNI ref and return + (*env)->ReleaseStringUTFChars(env, recv, java_cstr); + return nit_cstr; + `} + + redef fun to_s do return to_cstring.to_s +end + +redef class NativeString + # Get a Java string from this C string + # + # This instance is only valid until the next execution of Java code. + # You can use `new_local_ref` to keep it longer. + fun to_java_string: JavaString import sys, Sys.jni_env `{ + Sys sys = JavaString_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + return (*env)->NewStringUTF(env, recv); + `} +end + +redef class String + fun to_java_string: JavaString do return to_cstring.to_java_string +end + +redef extern class JavaObject + type SELF: JavaObject + + # Returns a global reference to the Java object behind this reference + # + # You must use a global reference when keeping a Java object + # across execution of Java code, per JNI specification. + fun new_global_ref: SELF import sys, Sys.jni_env `{ + Sys sys = JavaObject_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + return (*env)->NewGlobalRef(env, recv); + `} + + # Delete this global reference + fun delete_global_ref import sys, Sys.jni_env `{ + Sys sys = JavaObject_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + (*env)->DeleteGlobalRef(env, recv); + `} + + # Delete this local reference + fun delete_local_ref import sys, Sys.jni_env `{ + Sys sys = JavaObject_sys(recv); + JNIEnv *env = Sys_jni_env(sys); + (*env)->DeleteLocalRef(env, recv); + `} end