1 / 46

Das Java Native Interface

Das Java Native Interface. Wozu JNI?. Man benötigt Plattform-spezifische Features, die nicht durch die vorhandenen JAVA-Klassen bereitgestellt werden. Z.B.: Zugriff auf einen Bandroboter über die SCSI-Schnittstelle um eine grafische Oberfläche zur Bedienung des Roboters zu entwickeln.

svein
Télécharger la présentation

Das Java Native Interface

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Das Java Native Interface EDV2 - 02 - JavaNativeInterface

  2. Wozu JNI? • Man benötigt Plattform-spezifische Features, die nicht durch die vorhandenen JAVA-Klassen bereitgestellt werden. Z.B.: • Zugriff auf einen Bandroboter über die SCSI-Schnittstelle um eine grafische Oberfläche zur Bedienung des Roboters zu entwickeln. • Es ist eine Bibliothek mit Routinen vorhanden, die nicht in JAVA programmiert wurden. Z.B.: • Ausnutzung einer speziellen Hardware für numerische Berechnungen. • Ein kleiner zeitkritischer Programmabschnitt soll in einer hardwarenahen Sprache programmiert werden, um das Programm zu beschleunigen. Z.B.: • Textsuche in einem Editor • Skalarprodukt in einem numerischen Programm • Dreiecksberechnung in einem FEM-Code EDV2 - 02 - JavaNativeInterface

  3. Was bietet JNI? • Erzeugen, Analysieren und Verändern von JAVA-Objekten (einschließlich Felder und Zeichenketten) in C-Programmen. • Aufruf von JAVA-Methoden in C-Programmen. • Erzeugen und Abfangen von JAVA-Ausnahmen in C-Programmen. • Laden von JAVA-Klassen in C-Programmen. • Konsequente Typprüfung. EDV2 - 02 - JavaNativeInterface

  4. Aufruf von C-Routinen aus JAVA • Das Java Native Interface ermöglicht die Verbindung zwischen Programmen, die in JAVA geschrieben wurden mit Programmen, die in anderen Sprachen geschrieben sind, z.B. C, C++, Assembler, FORTRAN u.s.w. • Ziele: • Die strenge Schnittstellenprüfung von JAVA soll erhalten bleiben. • Es soll ermöglicht werden aus den anderen Sprachen heraus • JAVA-Objekte zu lesen und zu erzeugen, • JAVA-Methoden aufzurufen und • JAVA-Ausnahmen zu erzeugen. • Probleme: • Unterschiede bei den primitiven Datentypen • Unterschiede bei Objekttypen • Unterschiede bei der Parameterübergabe • Es werden eine Reihe von Tools zu Verfügung gestellt, die die Kopplung zwischen JAVA und C bzw. C++ vereinfachen. EDV2 - 02 - JavaNativeInterface

  5. HelloWorld: aufzurufendes C-Programm #include <stdio.h> void helloWorld() { printf("Hello, world!\n"); } Das Programm helloWorld sei vorgegeben und als Header-File hello.h sowie als Objektlibrary (LIB) hello.lib gespeichert. Problem: Wie kann helloWorld in einem JAVA-Programm aufgerufen werden. Lösung: Entwickeln einer Schnittstelle, die in einer oder mehreren JAVA-Klassen realisiert ist und den komfortablen Zugriff auf die Library ermöglicht. EDV2 - 02 - JavaNativeInterface

  6. Struktur HelloWorld.class Hello.class C_hello.h C_hello.c C_hello.dll hello.h hello.lib HelloWorld.java Hello.java EDV2 - 02 - JavaNativeInterface hello.c

  7. Aufrufendes JAVA-Programm public class Hello { public static native void helloWorld(); static { System.loadLibrary("C_hello"); } } EDV2 - 02 - JavaNativeInterface

  8. Das Tool javah • Das Tool javah dient dazu aus einem JAVA-Programm, das native-Methoden enthält, das header-File zu erzeugen, das die Schnittstelle zum Interface-Programm beschreibt. • Aufruf: javah –o h-file.h filename • Es wird ein header-File filename.h erzeugt, das die zu realisierenden Schnittstellen beschreibt. • Beispiel: javah -o C_hello.h Hello erzeugt C_hello.h EDV2 - 02 - JavaNativeInterface

  9. Erzeugtes header-File C_Hello.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class Hello */ #ifndef _Included_Hello #define _Included_Hello #ifdef __cplusplus extern "C" { #endif /* * Class: Hello * Method: helloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_Hello_helloWorld (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif EDV2 - 02 - JavaNativeInterface

  10. Ausfüllen der Schnittstelle • Es ist nun das Interface zu programmieren. • Dazu muss das in dem Header-File definierte Programm Java_Hello_helloWorldprogrammiert werden. • Die Parameter können zunächst vernachlässigt werden. #include "C_hello.h" /* * Class: Hello * Method: helloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_Hello_helloWorld (JNIEnv * env, jclass class) { helloWorld(); } EDV2 - 02 - JavaNativeInterface

  11. Übersetzen des C-Interfaces • Bei der Übersetzung muss die Library hello.dll eingebunden werden:hello.lib • Es müssen die JNI-spezifischen Include-Verzeichnisse angegeben werden:-Ic:\jdk1.3\include -Ic:\jdk1.3\include\win32 • Es muss eine DLL erzeugt werden:-LD -FeC_hello.dll • Insgesamt für MS-C-Compiler unter Windows:cl -Ic:\jdk1.3\include -Ic:\jdk1.3\include\win32 C_hello.c hello.lib-LD -FeC_hello.dll EDV2 - 02 - JavaNativeInterface

  12. Nutzung des Interfaces • Das so entwickelte Interface kann nun wie eine ganz normale JAVA-Klasse verwendet werden. public class HelloWorld { public static void main(String[] args) { Hello.helloWorld(); } } EDV2 - 02 - JavaNativeInterface

  13. Übergabe von Parametern • Problem: Datentypen von JAVA und C sind nicht kompatibel. • C-Datentypen sind nicht vollständig standardisiert und damit abhängig von Compiler, Betriebssystem und Hardware. • JAVA-Datentypen sind vollständig standardisiert und überall identisch. • Der Zugriff auf Attribute von Parameter-Objekten ist naturgemäß recht kompliziert. EDV2 - 02 - JavaNativeInterface

  14. Beispiel: EchoText #include <stdio.h> void helloWorld() { printf("Hello, world!\n"); } void echoText(const char *text) { printf("%s\n",text); } EDV2 - 02 - JavaNativeInterface

  15. Header-File:C_hello.h • Zusätzlich wird folgender Text generiert. • Er enthält einen zusätzlichen Parameter vom Typ jstring. • Problem: dieser Parameter muss in eine Zeichenkette vom C-Typ char* umgewandelt werden. /* * Class: Hello * Method: echoText * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_Hello_echoText (JNIEnv *, jclass, jstring); EDV2 - 02 - JavaNativeInterface

  16. Lesen des Parameters • Problem: Umwandlung des JAVA-String-Parameters in ein entsprechendes C-Format (const char *). • JNI stellt dafür diverse Methoden zur Verfügung. • Die Methoden sind erreichbar • in C: (*env)->Funktionsname(env,parameter); • In C++: env->Funktionsname(parameter); • Speziell lesen einer Unicode-Zeichenkette:GetStringUTFChars(env, text, isCopy) • Alle mit (*env)->GetXXXX angelegten C-Objekte müssen mit (*env)->ReleaseXXXX wieder freigegeben werden, wenn sie nicht mehr benötigt werde. EDV2 - 02 - JavaNativeInterface

  17. Beispiel JNIEXPORT void JNICALL Java_Hello_echoText (JNIEnv *env, jclass class, jstring text) { const char *ctext; ctext= (*env)->GetStringUTFChars(env, text, NULL); echoText(ctext); (*env)->ReleaseStringUTFChars(env, text, ctext); } EDV2 - 02 - JavaNativeInterface

  18. Erzeugen von JAVA-Strings • Zum Erzeugen eines JAVA-Strings aus einer C-Zeichenkette gibt es die Methodejstring NewStringUTF(JNIEnv *env, const char *bytes); • Achtung: Nicht vergessen, die im C-Teil reservierten Speicher freizugeben. EDV2 - 02 - JavaNativeInterface

  19. Beispiel: concatSrings char *concatStrings(const char *s1, const char *s2) { char *s; s=(char *)malloc(strlen(s1)+strlen(s2)+1,sizeof(s[0])); strcpy(s,s1); strcat(s,s2); return s; } EDV2 - 02 - JavaNativeInterface

  20. Hello.java public class Hello { public static native void helloWorld(); public static native void echoText(String text); public static native String concatStrings(String s1, String s2); static { System.loadLibrary("C_hello"); } } EDV2 - 02 - JavaNativeInterface

  21. C_hello.h /* * Class: Hello * Method: concatStrings * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_Hello_concatStrings (JNIEnv *, jclass, jstring, jstring); EDV2 - 02 - JavaNativeInterface

  22. C_hello.c /* * Class: Hello * Method: concatStrings * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_Hello_concatStrings (JNIEnv *env, jclass class, jstring s1, jstring s2) { const char *cs1; const char *cs2; char *cs; jstring s; cs1= (*env)->GetStringUTFChars(env, s1, NULL); cs2= (*env)->GetStringUTFChars(env, s2, NULL); cs = concatStrings(cs1, cs2); (*env)->ReleaseStringUTFChars(env, s1, cs1); (*env)->ReleaseStringUTFChars(env, s2, cs2); s=(*env)->NewStringUTF(env, cs); free(cs); return s; } EDV2 - 02 - JavaNativeInterface

  23. Zugriffsmethoden für Zeichenketten • C-ASCII-Zeichenkette JAVA-Zeichenkette • jstring NewStringUTF(JNIEnv *env, const char *bytes) • const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy) • void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf) • jsize GetStringUTFLength(JNIEnv *env, jstring string) • C-Unicode-Zeichenkette JAVA-Zeichenkette • jstring NewString (JNIEnv *env, const jchar *bytes) • const jchar* GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy) • void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *utf) • jsize GetStringLength(JNIEnv *env, jstring string) EDV2 - 02 - JavaNativeInterface

  24. Zugriff auf Felder • Wie für Zeichenketten gibt es für alle Arten von eindimensionalen Feldern entsprechende New-, Get-, Set- und Release-Methoden. • Dabei muss unterschieden werden zwischen den Zugriffsmethoden für Felder von primitiven Typen und Felder von Objekten. • jsize GetArrayLength(JNIEnv *env, jarray array)bestimmt die Länge des Feldes (array.length). • <ArrayType> New<PrimitiveType>Array(JNIEnv *env, jsize length) bzw.jarray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement)erzeugt ein neues Feld EDV2 - 02 - JavaNativeInterface

  25. Felder umkopieren • <NativeType> *Get<PrimitiveType>ArrayElements (JNIEnv *env, <ArrayType> array, jboolean *isCopy)erzeugt ein C-Feld und kopiert ggf. den Inhalt des JAVA-Feldes in das C-Feld. Änderungen des C-Feldes werden ggf. erst bei dem entsprechenden Release-Aufruf zurückkopiert. isCopy liefert JNI_TRUE, wenn das Feld kopiert wurde, JNI_FALSE sonst. • void Release<PrimitiveType>ArrayElements(JNIEnv *env, <ArrayType> array, <NativeType> *elems, jint mode)das C-Feld wird ggf. auf das JAVA-Feld zurückkopiert und die Ressourcen werden wieder freigegeben.mode steuert die Funktionen: • 0 : Kopieren der Daten und Ressourcen freigeben • JNI_COMMIT : Kopieren der Daten und Ressourcen nicht freigeben • JNI_ABORT: Ressourcen freigeben und Daten nicht kopieren EDV2 - 02 - JavaNativeInterface

  26. Teile von Feldern umkopieren • void Get<PrimitiveType>ArrayRegion(JNIEnv *env, <ArrayType> array, jsize start, jsize len,<NativeType> *buf)kopiert die Elemente start,...,start+len-1 aus dem JAVA-Feld array in das C-Feld buf • void Set<PrimitiveType>ArrayRegion(JNIEnv *env, <ArrayType> array, jsize start, jsize len,<NativeType> *buf)kopiert die Elemente start,...,start+len-1 aus dem C-Feld buf in das JAVA-Feld array EDV2 - 02 - JavaNativeInterface

  27. Elemente von Object-Arrays • jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)liest ein Element aus eine Object-Array • void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value)schreibt das Element value in das Feld EDV2 - 02 - JavaNativeInterface

  28. JAVA-Typen / C-Typen EDV2 - 02 - JavaNativeInterface

  29. Beispiel : matrixXvector void matrixXvector(int n, int m, double *matrix, double *vector, double *result) { int i,j; for (i=0;i<m;i++) { result[i]=0.0; for (j=0;j<n;j++) { result[i]+=matrix[i*n+j]*vector[j]; } } } EDV2 - 02 - JavaNativeInterface

  30. C_hello.h /* * Class: Hello * Method: matrixXvector * Signature: ([[D[D)[D */ JNIEXPORT jdoubleArray JNICALL Java_Hello_matrixXvector (JNIEnv *, jclass, jobjectArray, jdoubleArray); EDV2 - 02 - JavaNativeInterface

  31. C-hello.c JNIEXPORT jdoubleArray JNICALL Java_Hello_matrixXvector (JNIEnv *env, jclass clazz, jobjectArray matrix, jdoubleArray vector) { jsize n, m, i; jdouble *cMatrix; jdouble *cVector; jdouble *cResult; jboolean isCopy; jdoubleArray zeile; jdoubleArray result; n=(*env)->GetArrayLength(env, vector); m=(*env)->GetArrayLength(env, matrix); cVector=(*env)->GetDoubleArrayElements(env, vector, &isCopy); cMatrix=(jdouble *)calloc(m*n,sizeof(jdouble)); for (i=0;i<m;i++){ zeile=(jdoubleArray)((*env)->GetObjectArrayElement(env, matrix, i)); (*env)->GetDoubleArrayRegion(env, zeile, 0, n, &(cMatrix[i*n])); } cResult=(jdouble *)calloc(m,sizeof(jdouble)); matrixXvector(n, m, cMatrix, cVector, cResult); result=(*env)->NewDoubleArray(env, m); (*env)->SetDoubleArrayRegion(env, result, 0, m, cResult); free(cMatrix); free(cResult); (*env)->ReleaseDoubleArrayElements(env, vector, cVector, JNI_ABORT); return result; } EDV2 - 02 - JavaNativeInterface

  32. Zugriff auf JAVA-Objekte • Objekte können als Parameter an das Interface JAVA-C übergeben werden und es soll auf die Attribute und Methoden des Objektes zugegriffen werden. • Es soll auf JAVA-Klassen und deren statische Methoden zugegriffen werden, z.B. sollen die Methoden von StrictMath im C-Programm verwendet werden. • Es sollen im C-Programm Objekte erzeugt werden, z.B. um ein Objekt als return-Wert zurückgeben zu können. • Für die Unterscheidung der überladenenMethode spielen die Signaturen eine entscheidende Rolle. • Mit Hilfe der Signaturen lassen sich Datentypen eindeutig und relativ kompakt beschreiben. EDV2 - 02 - JavaNativeInterface

  33. Signaturen EDV2 - 02 - JavaNativeInterface

  34. Beispiele für Signaturen • Signatur von Feldern: Für jeden Index eine "[" anschließend die Signatur des Elementtyps.Z.B.: double[][] [[D • Signatur von Objekten: Lvoller-Klassen-Name;Z.B.: String  Ljava/lang/String; • Signatur von Methoden: (Signaturen der Parameter)Signatur des Wertes.Z.B.: double[] methode(int[][], boolean)([[DZ)[D EDV2 - 02 - JavaNativeInterface

  35. Zugriff auf Attribute von Objekten • Allgemeiner Typ von Objekten: jobject • Der Zugriff auf Attribute erfolgt über den FieldID. Um den FieldID zu bestimmen benötigt man: • Die Klasse zu der das Objekt gehört. • Den Namen des Attributes. • Die Signatur des Attributes. • Es muss unterschieden werden zwischen statischen und nichtstatischen Attributen und Methoden. • jclass GetObjectClass(JNIEnv *env, jobject obj)bestimmt die Klasse zu der das Objektobjgehört. • jclass FindClass(JNIEnv *env, const char *name)bestimmt die Klasse anhand ihres vollständigen Namens • Für interne Klassen gilt der Klassenname: Klasse$interneKlasse EDV2 - 02 - JavaNativeInterface

  36. nichtstatische Attribute • jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)bestimmt aus der Klasse, dem Attributnamen und seiner Signatur den FieldID. • <NativeType> Get<PrimitiveType>Field(JNIEnv *env, jobject obj, jfieldID fieldID)liest den Wert des Attributes, funktioniert auch für Objekt-Typen • void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, <NativeType> value)schreibt einen Wert in das Attribut EDV2 - 02 - JavaNativeInterface

  37. Beispiel ... method(JNIEnv *env, jclass class, jobject obj) { jclass objClass; jfieldID attrID; jint intAttr; objClass=(*env)->GetObjectClass(env, obj); attrID=(*env)->GetFieldID(env, class, "dimension", "I"); intAttr=(*env)->GetIntField(env, obj, attrID); intAttr=2*intAttr+77; (*env)->SetIntField(env, obj, attrID, intAttr); } EDV2 - 02 - JavaNativeInterface

  38. statische Attribute • jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)bestimmt aus der Klasse, dem Attributnamen und seiner Signatur den FieldID. • <NativeType> GetStatic<PrimitiveType>Field(JNIEnv *env, jclass clazz, jfieldID fieldID)liest den Wert des Attributes, funktioniert auch für Objekt-Typen • void SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID, <NativeType> value)schreibt einen Wert in das Attribut EDV2 - 02 - JavaNativeInterface

  39. Beispiel ... method(JNIEnv *env, jclass class, jobject obj) { jclass objClass; jfieldID attrID; jint intAttr; objClass=(*env)->GetObjectClass(env, obj); attrID=(*env)->GetStaticFieldID(env, class, "dimension", "I"); intAttr=(*env)->GetStaticIntField(env, class, attrID); intAttr=2*intAttr+77; (*env)->SetStaticIntField(env, class, attrID, intAttr); } EDV2 - 02 - JavaNativeInterface

  40. nichtstatische Methoden von Objekten • jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)bestimmt den MethodID einer Methode. Bei überladenen Methoden wird die sie durch die Signatur identifiziert. • Diese Varianten des Aufrufs von JAVA-Methoden unterscheiden sich nur in der Art der Übergabe der Parameter. • <NativeType> Call<PrimitiveType>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...)alle Parameter werden nacheinander angegeben • <NativeType> Call<PrimitiveType>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)die Parameter werden als Feld übergeben • <NativeType> Call<PrimitiveType>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)die Parameter werden als Liste übergeben EDV2 - 02 - JavaNativeInterface

  41. Beispiel method(JNIEnv *env, jclass class, jobject obj) { jclass objClass; jmethodID methID; objClass=(*env)->GetObjectClass(env, obj); methID=(*env)->GetMethodID(env, objClass, "setDimension", "(I)V"); (*env)->CallVoidMethod(env, obj, methID, 777); } EDV2 - 02 - JavaNativeInterface

  42. Aufruf statischer Methoden • jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) • <NativeType> CallStatic<PrimitiveType>Method (JNIEnv *env, jclass clazz, jmethodID methodID, ...)alle Parameter werden nacheinander angegeben • <NativeType> CallStatic<PrimitiveType>MethodA (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)die Parameter werden als Feld übergeben • <NativeType> CallStatic<PrimitiveType>MethodV (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)die Parameter werden als Liste übergeben EDV2 - 02 - JavaNativeInterface

  43. Beispiel ... jdouble sin(JNIEnv *env, jclass clazz, jdouble x) { jclass cl; jmethodID sinID; jdouble sx; cl=(*env)->FindClass(env, "java/lang/StrictMath"); sinID=(*env)->GetStaticMethodID(env, cl, "sin", "(D)D"); sx=(*env)->CallStaticDoubleMethod(env, cl, sinID, x); return sx; } EDV2 - 02 - JavaNativeInterface

  44. Neue JAVA-Objekte erzeugen • jobject AllocObject(JNIEnv *env, jclass clazz)erzeugt eine neues Objekt der Klasse clazz ohne einen Konstruktor aufzurufen • jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...) • jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args) • jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)erzeugt ein neues Objekt, wobei der Konstruktor mit der ID methodID und den angegebenen Parametern benutzt wird. • Als Name des Konstruktors wird "<init>" verwendet. Als Signatur für den return-Wert "V". • Bei internen Klassen ist die Parameterliste am Anfang um einen Parameter jclass zu erweitern. Diesem ist der Parameter class der C-Methode zu übergeben. EDV2 - 02 - JavaNativeInterface

  45. Beispiel ...jobject method(JNIEnv *env, jclass clazz) { jclass tsClass; jmethodID tsConst; jobject tsObj; jmethodID tsAdd; tsClass=(*env)->FindClass(env, "java/util/TreeSet"); tsConst=(*env)->GetMethodID(env, tsClass, "<init>", "()V"); tsObj=(*env)->NewObject(env, tsClass, tsConst); tsAdd=(*env)->GetMethodID(env, tsClass, "add", "(Ljava/lang/Object;)Z"); (*env)->CallBooleanMethod(env, tsObj, tsAdd, (*env)->NewStringUTF(env, "Mueller")); (*env)->CallBooleanMethod(env, tsObj, tsAdd, (*env)->NewStringUTF(env, "Meier")); return tsObj; } EDV2 - 02 - JavaNativeInterface

  46. Das Tool javap • Mit javap kann man class-Files bearbeiten. Javap liefert: • Ausgabe des Byte-Codes (-c) • Tabelle der lokalen Variablen (-l) • Signaturen alle Methoden (-s) EDV2 - 02 - JavaNativeInterface

More Related