Using the Java Native Interface with Delphi
(Part Two - Techniques and Examples)

Matthew Mead

Home Page (on the Web) - News and Updates

Part One - Introduction and Tutorial
Part Two - Techniques and Examples
Part Three - The Invocation API


Contents

OverviewWhat's here?
SignaturesHow to describe a function's parameters and return type
ConceptsThese are examples of what you will learn here. The test in brackets (e.g. [Test 4]), indicates the test number that demonstrates this in the included code. Examples that don't include a test number are still present in the code, however, they were not part of the original C++ implementation so they don't have a test case assigned.
  1. Simple Function Call - Call a Delphi procedure that doesn't take any arguments. [Test 1]
  2. Passing/Returning Simple Types - Demonstrates passing 2 integer values to a function that multiplies them together and then returns the result. [Test A]
  3. Passing an Array of Primitive Types to Delphi - Demonstrates passing a Java Array (of type byte) to the Delphi DLL. The DLL initializes each element of the Java Array. This example also shows how to overload a native method.
  4. Passing an Array of Objects to Delphi - Demonstrates passing a Java Array of objects to the Delphi DLL. This example also shows how to access each object in the array and print it out using the object's toString method. (This method is present in almost all Java objects.) In order to invoke the toString method, the Delphi DLL will need to call back into Java. [Tests 5, 6]
  5. Passing a 2-Dimensional Array to Delphi - Demonstrates passing a 2-dimensional array to Delphi. The method shown here can be applied to 3-dimensional arrays as well. [Test 10]
  6. Calling a Method of a Java Object from Delphi - Demonstrates invoking a method on a Java object that was passed into the DLL. (See Concept #4, Passing an Array of Objects to Delphi for the example.)
  7. Creating Java Objects within Delphi - Demonstrates creating Java objects in Delphi and passing them back to Java. [Test 7]
  8. Accessing Fields of a Java Object from Delphi - Demonstrates accessing fields (members) of a Java object that was passed into the DLL. [Test 4]
  9. Handling Java Exceptions within Delphi - Demonstrates how to detect and suppress Java exceptions within Delphi. [Test 8]
  10. Causing a Java Exception within Delphi - Demonstrates how to cause (throw) a Java exception. [Test 9]
TJNIEnv A closer look at the TJNIEnv wrapper class.
Summary What's next?
Overview
In Part One, I gave an introduction to Using the Java Native Interface with Delphi. I showed (in painful detail) an example of printing "Hello World!" from a Delphi DLL called from Java. In Part Two, I will show more sophisticated techniques using the Java Native Interface with Delphi. You will learn concepts such as how to access fields of Java objects and how to call methods of a Java class. You will also see how to create Java objects within a Delphi DLL and pass them back and forth between Java and Delphi. Essentially, these are some of the concepts discussed in this document:

This part of Using the Java Native Interface with Delphi is based on some JNI research I did using C++ a couple of years or so ago. This work can be found here. For this document, I essentially translated the C++ DLL to a Delphi DLL. (The lines of C++ code translated to Delphi code almost one-for-one.) In this version of that work, I won't be explaining a lot of the fundamentals of using the JNI. You can refer to Part One of Using the Java Native Interface with Delphi for explanations of those concepts. This document focuses on putting those fundamentals to use.

This part takes more of a Learn By Example approach to the JNI. Because of this, I don't spend a lot of time explaining in detail each of the many JNI functions that are used. I leave that up to Sun's JNI Documentation. This document is meant to provide a convenient place to find out how to do common tasks when using the Java Native Interface. The examples here are not exhaustive, meaning that I don't have examples for everything you'd want to do with the JNI. As I encounter other/better examples, I will add them here.

One last thing: My original work with these JNI concepts also included some rudimentary benchmarks. One of the goals was to compare the performance between Sun's JDK and Microsoft's JDK, as well as the performance differences on Windows, Solaris, and Linux. This document doesn't discuss those goals, however, some of those tests still exist in the Java files. Rather than remove them, I just left them in the files with the hope that, at some later point, I might come back and revisit them.

Back to top

Signatures
A function's signature consists of the function's name and parameters. The function's parameters are subject to these constraints:
Note that not all languages have these criteria. For example, Ada, Python, and Visual Basic (among others) can pass parameters by Name, so the order is not required.
There are several functions in the JNI that require, as a parameter, the signature of another function. The type of this parameter is a string. The table below shows how Java types are mapped into characters (e.g. boolean is mapped as the uppercase letter Z) and strings (e.g. Java String is mapped as the literal string Ljava/lang/String;). It then just becomes a matter of building these strings up based on the parameters and return types of Java methods.

Java TypeSignature
booleanZ
byteB
charC
doubleD
floatF
intI
longJ
voidV
objectLfully-qualified-class;
type[][type
method signature( arg-types) ret-type

Examples:

MethodSignature
void f1()()V
int f2(int, long)(IJ)I
boolean f3(int[])([I)B
double f4(String, int)(Ljava/lang/String;I)D
void f5(int, String [], char)(I[Ljava/lang/String;C)V

If you recall from Part One, all native functions have two hidden parameters. These parameters are not included in this signature (since these signatures refer to Java methods.) So, for example, a Java method that doesn't take any arguments and doesn't return a value would have the signature:

  ()V
Later, you will see how these signatures are used by Delphi when invoking Java methods.

Back to top

Concepts
In this document, each concept is explained with an example that implements some code in Java and/or Delphi. For example, one concept to learn is how to call a void function (a procedure in Delphi) that doesn't take any arguments. This is done in this document by creating a procedure in Delphi and printing the words Hello World! to the screen.

As in Part One, this part is implemented in 3 files:

Each function contains a header comment that shows: Incidentally, most of the function comments can be automatically generated with javah, a tool that creates C/C++ header files from Java class files. I used this tool to create this information and then copied it into the Delphi code.

Back to top

Concept #1 - Simple Function Call
This is an example of a function that doesn't take any parameters and doesn't return any value. This is essentially the Hello World function described in Part One.
(****************************************************************************
 *  Java declaration:
 *     native public void displayHelloWorld();
 *
 *  The canonical first method.
 *
 *  Class:     Native
 *  Method:    displayHelloWorld
 *  Signature: ()V
 *)
procedure Java_Native_displayHelloWorld(PEnv: PJNIEnv; Obj: JObject); stdcall;
begin
  WriteLn('Hello world!');
end;

Back to top

Concept #2 - Passing/Returning Simple Types
This is an example of a function that expects 2 integer parameters, multiplies them together, and returns the result.
(****************************************************************************
 *  Java declaration:
 *     native public void multiplyIntegers(int op1, int op2);
 *
 *  Multiplies 2 integers and returns the result.
 *
 *  Class:     Native
 *  Method:    multiplyIntegers
 *  Signature: (II)I
*)
function Java_Native_multiplyIntegers(PEnv: PJNIEnv; Obj: JObject; Op1: JInt; Op2: JInt): JInt; stdcall;
begin
  Result := Op1 * Op2;
end;

Back to top

Concept #3 - Passing an Array of Primitive Types to Delphi
This example shows how to pass a Java Array to a Delphi method. Each element of the array is set to a value (specified as a parameter.) The native method initializeByteArray is an overloaded method within the Delphi DLL. The original initializeByteArray method required an extra parameter: the number of times to initialize the array. Obviously, you only need to initialize each member once, but the original version is used to test the performance of initializing an array many times. However, this example only requires a single initialization, so I overloaded the method and exported it with the name Java_Native_initializeByteArrayOnce. This has the benefits of allowing both versions to be called from Java and also maintains compatibility with the existing Java code, namely Main.java.
(****************************************************************************
 *  Java declaration:
 *     native public void initializeByteArray(byte[] byteArray, int count, byte value);
 *
 *  Initializes an array 'Count' times with the Value 'Value'. This function
 *  is mainly used to test the performance of array accesses in native code.
 *
 *  Class:     Native
 *  Method:    initializeByteArray
 *  Signature: ([BIB)V
 *)
procedure Java_Native_initializeByteArray(PEnv: PJNIEnv; Obj: JObject; ByteArray: JByteArray; Count: JInt; Value: JByte); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} overload;
var
  Elements: PJByte;
  PE: PJByte;
  Len: JSize;
  I, J: Longint;
  IsCopy: JBoolean;
  JVM: TJNIEnv;
begin
    // Create an instance of the Java environment
  JVM := TJNIEnv.Create(PEnv);

    // Get elements of the array
  Elements := JVM.GetByteArrayElements(ByteArray, IsCopy);

    // Get length of the array
  Len := JVM.GetArrayLength(ByteArray);

    // Loop through the array 'Count' times, assigning 'Value' to each
    // element.
  for I := 0 to Count - 1 do
  begin
    PE := Elements;
    for J := 0 to Len - 1 do
    begin
      PE^ := Value;
      Inc(PE);
    end;
  end;

    // Important! From Sun's documentation:
    // Since the returned array may be a copy of the Java array, changes made
    // to the returned array will not necessarily be reflected in the original
    // array until Release<PrimitiveType>ArrayElements() is called.
  JVM.ReleaseByteArrayElements(ByteArray, Elements, 0);

end;


Notes:

Back to top

Concept #4 - Passing an Array of Objects to Delphi
This example shows how to access each element of an array of Java objects. For each object in the array, the object's toString method will be invoked on the object. Almost all Java objects implement the toString method, which prints something intelligent about the value of the object. There are some interesting concepts to recognize here:
  1. It doesn't matter what kind of object is in the array. This function will handle all types and the toString method will act correctly (since it's being invoked on the object itself.)
  2. The DLL is actually calling back into Java to do the printing. This is because, although the object has been passed into the DLL (as an element of the array), it's really only a reference to the object. The object's methods still exist in the Java code that called the DLL.
(****************************************************************************
 *  Java declaration:
 *     native public void printObjectArray(Object[] array);
 *
 *  Given an array of Objects, each element is printed using the
 *  'toString' method of the Object.
 *
 *  Class:     Native
 *  Method:    printObjectArray
 *  Signature: ([Ljava/lang/Object;Z)V
 *)
procedure Java_Native_printObjectArray(PEnv: PJNIEnv; Obj: JObject; ObjArray: JObjectArray; Print: JBoolean); stdcall;
var
  Cls: JClass;
  Mid: JMethodID;
  Ob: JObject;
  Element: JObject;
  S: JString;
  Str: string;
  Len, I: Integer;
  JVM: TJNIEnv;
begin
  JVM := TJNIEnv.Create(PEnv);

    // Get length of the array
  len := JVM.GetArrayLength(ObjArray);

    // Make sure we have at least one object in the array
  if Len < 1 then
    exit;

    // Get an element of the array so we can get the right 'toString' method
  Ob := JVM.GetObjectArrayElement(ObjArray, 0);

    // Get the class associated with this object
  Cls := JVM.GetObjectClass(Ob);

  if Cls = nil then begin
    WriteLn('Can''t GetObjectClass');
    exit;
  end;

    // Get method ID for the 'toString' method of this object's class
  Mid := JVM.GetMethodID(Cls, 'toString', '()Ljava/lang/String;');

    // We will check this also
  if Mid = nil then begin
    WriteLn('Can''t GetMethodID for toString');
    exit;
   end;

    // Loop the array of objects and print out each one using
    // the 'toString' method of its ancestor class Object
  for I := 0 to Len - 1 do begin

      // Get the next element from the array
    Element := JVM.GetObjectArrayElement(ObjArray, i);

      // Call the 'toString' method, which returns a String representation
      // of Rectangle object.
    S := JVM.CallObjectMethodA(Element, Mid, nil);

      // The actual printing can be turned on/off. This was useful during
      // debugging when passing thousands of elements into the procedure.
    if Print <> False then begin
      Str := JVM.JStringToString(S);
      WriteLn(Str);
    end;
  end;

  JVM.Free;
end;

Notes:

Back to top

Concept #5 - Passing a 2-Dimensional Array to Delphi
This examples shows how to pass a 2-D array to Delphi. It is straight-forward to apply this technique to 3-D arrays as well.
(****************************************************************************
 *  Java declaration:
 *     native public void pass2DByteArray(byte[][] array);
 *
 *  Pass a 2-D array of Bytes from Java. This method will retrieve each
 *  element from the arrays, print it, then multiply it by 10 and store
 *  the new Value back into the array. This is to show access/updating
 *  of 2-D arrays within native code. The process would be similar for
 *  3-D arrays.
 *
 *  Class:     Native
 *  Method:    pass2DByteArray
 *  Signature: ([[B)V
 *)
procedure Java_Native_pass2DByteArray(PEnv: PJNIEnv; Obj: JObject; Array2D: JObjectArray); {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
var
  NumArrays: JSize;
  Len: JSize;
  I, J: Integer;
  JBArray: JByteArray;
  Elements, Walker: PJByte;
  IsCopy: JBoolean;
  JVM: TJNIEnv;
begin
    // Create an instance of the Java environment
  JVM := TJNIEnv.Create(PEnv);

    // Get length of the array (number of arrays)
  NumArrays := JVM.GetArrayLength(Array2D);

  Writeln('In native method printing 2-D byte array.');
  Writeln('Each element is then multiplied by 10 and updated.');

    // Loop over each array
  for I := 0 to NumArrays - 1 do
  begin

      // Get the object at the i'th position (it's an array of Bytes)
    JBArray := JVM.GetObjectArrayElement(Array2D, i);

      // Get the length of this array of Bytes
    Len := JVM.GetArrayLength(JBArray);

      // Get the elements from the Byte array
    Elements := JVM.GetByteArrayElements(JBArray, IsCopy);

      // We will "walk" the array with this pointer
    Walker := Elements;

      // Print each element, then multiply the Value by 10
      // and put it back into the array. (This is to prove that
      // the array elements have changed when this function returns
      // to Java code.
    for J := 0 to Len - 1 do
    begin
      Writeln(Format('%d,%d = %d', [I, J, Walker^]));

        // Update the element (just multiply it by 10)
      Walker^ := Walker^ * 10;
      Inc(Walker);
    end;

      // Important! From Sun's documentation:
      // Since the returned array may be a copy of the Java array, changes made
      // to the returned array will not necessarily be reflected in the original
      // array until Release<PrimitiveType>ArrayElements() is called.
    JVM.ReleaseByteArrayElements(JBArray, Elements, 0);

  end;

  JVM.Free;
end;

Notes:

Back to top

Concept #6 - Calling a Method of a Java Object from Delphi
(See Concept #4, Passing an Array of Objects to Delphi for the example.)

Back to top

Concept #7 - Creating Java Objects within Delphi
The example shows how to create a Java object within the Delphi DLL. An array of Java objects is created and then passed back to Java. The objects created are rectangles (java/awt/Rectangle) and we don't do anything special with them. Each Rectangle is simply created and initialized to an arbitrary size. Then, they are passed back to Java where they are printed out (using the object's toString method) for verification.
(****************************************************************************
 *  Java declaration:
 *     native public jobjectarray returnRectArray(int size);
 *
 *  This function creates an array of 'size' Rectangles and returns them
 *  to the Java caller. First, the array is created, then each element
 *  is assigned a Rectangle object.
 *
 *  Class:     Native
 *  Method:    returnRectArray
 *  Signature: (I)[Ljava/awt/Rectangle;
 *)
function Java_Native_returnRectArray(PEnv: PJNIEnv; Obj: JObject; Size: JInt): JObjectArray; stdcall;
var
  Cls: JClass;
  Mid: JMethodID;
  Element: JObject;
  JOArray: JObjectArray;
  I: Integer;
  Args: array[0..3] of JValue;
  JVM: TJNIEnv;
begin
  JVM := TJNIEnv.Create(PEnv);

    // Find the Rectangle class
  Cls := JVM.FindClass('java/awt/Rectangle');
  if Cls = nil then begin
    WriteLn('Can''t FindClass(java/awt/Rectangle');
    Result := nil;
    exit;
  end;

    // Get its constructor (the one that takes 4 integers)
  Mid := JVM.GetMethodID(Cls, '<init>', '(IIII)V');
  if Mid = nil then begin
    WriteLn('Can''t get MethodID for Rectangle constructor');
    Result := nil;
    exit;
  end;

    // Allocate the array of Rectangles
  JOArray := JVM.NewObjectArray(Size, Cls, nil);

    // Now initialize each one to a Rectangle
  for I := 0 to Size - 1 do begin

      // Create a new Rectangle object
    Args[0].i := 0;
    Args[1].i := 0;
    Args[2].i := 5 * I;
    Args[3].i := 10 * I;
    Element := JVM.NewObjectA(Cls, Mid, @args);

      // Assign the Rectangle to an element of the array
    JVM.SetObjectArrayElement(JOArray, I, Element);

  end;

    // Return the array back to the Java client
  Result := JOArray;

  JVM.Free;
end;

Notes:

Back to top

Concept #8 - Accessing Fields of a Java Object from Delphi
This example shows how to access fields (members) of the Java object/class. There are four fields declared in the class, each demonstrates a particular point:
  1. public String w - a public object, demonstrates accessing an object.
  2. public int x - a public int, demonstrates accessing a primitive type.
  3. private int y - a private int, demonstrates accessing a private field. (Yes!)
  4. public static int z - a public static int, demonstrates accessing a static field. (class member)
(****************************************************************************
 *  Java declaration:
 *     native public void printWXYZ();
 *
 *  Prints out four members of the Native object, w, x, y, and z. This
 *  function acts sort of like the traditional 'toString' method in Java.
 *  The members are declared in Native.java as such:
 *
 *  public String w;       // public Object
 *  public int x;          // public
 *  private int y;         // private (no protection here)
 *  public static int z;   // public static
 *
 *  The return Value from each GetFieldID call should be checked.
 *  I don't check because I'm trying to keep the focus on the calls.
 *
 *  Class:     Native
 *  Method:    printWXYZ
 *  Signature: ()V
 *)
procedure Java_Native_printWXYZ(PEnv: PJNIEnv; Obj: JObject); stdcall;
var
  X, Y, Z: JInt;
  W: JString;
  FID: JFieldID;
  Cls: JClass;
  Str: string;
  JVM: TJNIEnv;
begin
  JVM := TJNIEnv.Create(PEnv);

  Cls := JVM.GetObjectClass(Obj);

    // w is a String
  FID := JVM.GetFieldID(Cls, 'w', 'Ljava/lang/String;');

    // Get the Object (String) w.
  W := JVM.GetObjectField(Obj, FID);

    // x is a non-static public field
  FID := JVM.GetFieldID(Cls, 'x', 'I');

    // Get the int
  X := JVM.GetIntField(Obj, FID);

    // y is a non-static private field, same as public here
  FID := JVM.GetFieldID(Cls, 'y', 'I');

    // Get the int
  Y := JVM.GetIntField(Obj, FID);

    // z is a _static_ public field, so call different method
  FID := JVM.GetStaticFieldID(Cls, 'z', 'I');

    // Get static int
  Z := JVM.GetStaticIntField(Cls, FID);

    // Convert Java string into Delphi string
  Str := JVM.JStringToString(W);

    // Sort of like the traditional 'toString' output
  WriteLn(Format('[w = %s, x = %d, y = %d, z = %d]', [Str, X, Y, Z]));

  JVM.Free;
end;

Notes:

Back to top

Concept #9 - Handling Java Exceptions within Delphi
This example shows how to detect a Java exception. The code purposely attempts to invoke a non-existent method on a Java object, called nonexistent. This causes a run-time exception that is detected within the Delphi code.
(****************************************************************************
 *  Java declaration:
 *     native public void handleException();
 *
 *  Causes an exception in the JVM, but detects it and suppresses it
 *
 *  Class:     Native
 *  Method:    handleException
 *  Signature: ()V
 *)
procedure Java_Native_handleException(PEnv: PJNIEnv; Obj: JObject); stdcall;
var
  Cls: JClass;
  AException: JThrowable;
  JVM: TJNIEnv;
begin
  JVM := TJNIEnv.Create(PEnv);

    // Get the class to which this object belongs
  Cls := JVM.GetObjectClass(Obj);

    // Attempt to get the ID of the 'nonexistent' member, which, not by
    // chance, doesn't exist!
  JVM.GetFieldID(Cls, 'nonexistent', 'Ljava/lang/String;');

    // Check for exception
  AException := JVM.ExceptionOccurred;

    // exception is non-zero if an exception occurred
  if (AException <> nil) then begin

    //WriteLn('Exception occurred in Native code and was handled. This was the exception:');
    Writeln(Format('Exception handled in Main.cpp: %d', [DWORD(AException)]));

      // This call will print out a description of the exception
    //JVM.ExceptionDescribe;

      // Clear the exception so the JVM doesn't react to it after we handled it
    JVM.ExceptionClear;

  end;

  JVM.Free;
end;

Notes:

Back to top

Concept #10 - Causing Java Exceptions within Delphi
(****************************************************************************
 *  Java declaration:
 *     native public void causeException();
 *
 *  Causes an exception in the JVM, but fails to catch it. Thus, it is
 *  propagated back to the JVM.
 *
 *  Class:     Native
 *  Method:    causeException
 *  Signature: ()V
 *)
procedure Java_Native_causeException(PEnv: PJNIEnv; Obj: JObject); stdcall;
var
  Cls: JClass;
  JVM: TJNIEnv;
begin
  JVM := TJNIEnv.Create(PEnv);

    // Get the class to which this object belongs
  Cls := JVM.GetObjectClass(Obj);

    // Attempt to get the ID of the 'nonexistent' member, which, not by
    // chance, doesn't exist!
  JVM.GetFieldID(Cls, 'nonexistent', 'Ljava/lang/String;');

    // An exception has occurred, but it has not been suppressed.
    // The JVM will detect it and catch it.
    // Because we don't call this: JVM.ExceptionClear,
    // the JVM will react.

  JVM.Free;
end;

Back to top

TJNIEnv: The Wrapper Class
TJNIEnv is a thin wrapper around the JNI API, allowing it to look and feel a little object oriented. It's called a thin wrapper because it doesn't really hide a lot of the underlying data and functions. It's only a slight convenience. More importantly, however, is that it is more consistent with the way OO languages, such as Delphi, are coded. Many APIs are simply sets of global functions that operate on the data you provide. The same is true for the Java Native Interface API.

To get an idea of what the Delphi code would look like without using TJNIEnv, look at the printWXYZ method below. This is a modified version of the method used to describe Concept #8 above.

procedure Java_Native_printWXYZ(PEnv: PJNIEnv; Obj: JObject); stdcall;
var
  X, Y, Z: JInt;
  W: JString;
  FID: JFieldID;
  Cls: JClass;
  Str: string;
  IsCopy: JBoolean;  // added for GetStringChars
  Chars: PJChar;     // added for GetStringChars
begin
    // Get the class associated with this object
  Cls := PEnv^.GetObjectClass(PEnv, Obj);

    // w is a String
  FID := PEnv^.GetFieldID(PEnv, Cls, 'w', 'Ljava/lang/String;');

    // Get the Object (String) w.
  W := PEnv^.GetObjectField(PEnv, Obj, FID);

    // x is a non-static public field
  FID := PEnv^.GetFieldID(PEnv, Cls, 'x', 'I');

    // Get the int
  X := PEnv^.GetIntField(PEnv, Obj, FID);

    // y is a non-static private field, same as public here
  FID := PEnv^.GetFieldID(PEnv, Cls, 'y', 'I');

    // Get the int
  Y := PEnv^.GetIntField(PEnv, Obj, FID);

    // z is a _static_ public field, so call different method
  FID := PEnv^.GetStaticFieldID(PEnv, Cls, 'z', 'I');

    // Get static int
  Z := PEnv^.GetStaticIntField(PEnv, Cls, FID);

    // Convert Java string into Delphi string
  Chars := PEnv^.GetStringChars(PEnv, W, IsCopy);
  Str := string(Chars);
  PEnv^.ReleaseStringChars(PEnv, W, Chars);

    // Sort of like the traditional 'toString' output
  WriteLn(Format('[w = %s, x = %d, y = %d, z = %d]', [Str, X, Y, Z]));
end;
There are a few changes that stand out:

One thing you may be saying to yourself is "I don't see the great benefit of using wrappers around the API" For the TJNIEnv class, I would partially agree. There seems to be almost a one-to-one correspondence between the code you write with the wrapper class compared to the code you write without it. But don't forget that a major factor in using classes is to be consistent with Delphi's programming style. Also, this allows the TJNIEnv class to be extended at a later time to provide more functionality than it does now.

In Part Three of Using the Java Native Interface with Delphi you will see another wrapper class called TJavaVM which is not merely a thin layer, but a full-blown OO interface to the Invocation API of the JNI. Among other things, this class handles loading and unloading of DLLs at the appropriate times, relieving the programmer of this burden.

Back to top

Summary
Part Two of Using the Java Native Interface with Delphi shows by example how to perform many of the common tasks necessary when using the JNI. These tasks are not specific to Delphi, but are required by any language that desires to interface with Java using the JNI. These examples show, from a Delphi perspective using Delphi code, how to interact with Java at runtime. After reading this document, you should have a good foundation to further explore Delphi and the Java Native Interface.

Part Three introduces you to the Invocation API, which is the term given to a subset of the JNI that deals with embedding the Java Virtual Machine into another program. In our case, this other program will be a Delphi program.

Download the files used in this document.
Using the Java Native Interface with Delphi (Part One)
Using the Java Native Interface with Delphi (Part Three)
Helpful resources (from Part One.)

Back to top


Copyright © 2000-2002 Matthew Mead. All Rights Reserved.