The Java module requires your system to support shared libraries and dynamic loading. This is the commonly used method to load JNI code so your system is more than likely to support this.
%swig -java -proxy example.i
This will produce 2 files. The file example_wrap.c contains all of the C code needed to build a Java module. To build a Java module, you will need to compile the file example_wrap.c to create a shared library. When proxy classes are enabled, SWIG may also produce many .java files, but this is described later.
swig -java -help
Java specific options | |
---|---|
-package <java package> | set the name of the package for the generated classes |
-proxy | generate proxy class a.k.a. shadow classes |
-nofinalize | do not generate finalizer methods in proxy classes |
/usr/java/include /usr/java/include/<operating_system>
The exact location may vary on your machine, but the above locations are typical.
Unfortunately, the process of building a shared object file varies on every single machine so you may need to read up on the man pages for your C compiler and linker.$ swig -java -proxy example.i $ gcc -c example_wrap.c -I/usr/java/include -I/usr/java/include/solaris $ ld -G example_wrap.o -o libexample.so
When building a dynamic module, the name of the output file is important. If the name of your SWIG module is "example", the name of the corresponding object file should be "libexample.so" (or equivalent depending on your machine, see Dynamic linking problems for more information). The name of the module is specified using the %module directive or -module command line option.
Compile all the Java files and run:// main.java public class main { static { System.loadLibrary("example"); } public static void main(String argv[]) { System.out.println(example.fact(4)); } }
$ javac *.java $ java main 24 $
Now, assuming all went well, SWIG will be automatically invoked when you build your project. When doing a build, any changes made to the interface file will result in SWIG being automatically invoked to produce a new version of the wrapper file. The Java classes that SWIG output should also be compiled into .class files. To run the native code in the DLL (example.dll), make sure that it is in your path then run your Java program which uses it, as described in the previous section. If the library fails to load have a look at Dynamic linking problems.
# Makefile for building a Java extension SRCS = example.c IFILE = example INTERFACE = $(IFILE).i WRAPFILE = $(IFILE)_wrap.c # Location of the Visual C++ tools (32 bit assumed) TOOLS = c:\msdev TARGET = example.dll CC = $(TOOLS)\bin\cl.exe LINK = $(TOOLS)\bin\link.exe INCLUDE32 = -I$(TOOLS)\include MACHINE = IX86 # C Library needed to build a DLL DLLIBC = msvcrt.lib oldnames.lib # Windows libraries that are apparently needed WINLIB = kernel32.lib advapi32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib # Libraries common to all DLLs LIBS = $(DLLIBC) $(WINLIB) # Linker options LOPT = -debug:full -debugtype:cv /NODEFAULTLIB /RELEASE /NOLOGO \ /MACHINE:$(MACHINE) -entry:_DllMainCRTStartup@12 -dll # C compiler flags CFLAGS = /Z7 /Od /c /nologo JAVA_INCLUDE = -ID:\jdk1.3\include -ID:\jdk1.3\include\win32 java:: swig -java -proxy -o $(WRAPFILE) $(INTERFACE) $(CC) $(CFLAGS) $(JAVA_INCLUDE) $(SRCS) $(WRAPFILE) set LIB=$(TOOLS)\lib $(LINK) $(LOPT) -out:example.dll $(LIBS) example.obj example_wrap.obj javac *.java
To build the extension, run NMAKE (you may need to run vcvars32 first). This is a pretty simplistic Makefile, but hopefully its enough to get you started.
Will produce the following JNI C function:%module example extern int fact(int n);
This will in turn call the desired fact function. The JNI naming mangling isn't pretty, but you can see from the above that the native function call is expecting a class 'example'. SWIG outputs the JNI Java code into the example class:JNIEXPORT jint JNICALL Java_example_fact(JNIEnv *jenv, jclass jcls, jint jarg0) {
It can be used as follows from Java:public class example { public final static native int fact(int jarg0); }
System.out.println(example.fact(4));
/* SWIG interface file with global variables */ %module example ... extern int My_variable; ...
Now in Java :
The value returned by the getter will always be up to date even if the value is changed in C. The setter will not be generated if the variable is a C 'const'.// Print out the value of a C global variable System.out.println("My Variable = " + example.get_My_variable()); //Set the value of a C global variable example.set_My_variable(100);
will be wrapped with the following Java:enum color { RED, BLUE, GREEN };
public class example { ... maybe some other functions ... public final static native int get_RED(); public final static native int get_BLUE(); public final static native int get_GREEN(); // enums and constants public final static int RED = get_RED(); public final static int BLUE = get_BLUE(); public final static int GREEN = get_GREEN(); }
will be wrapped with the following Java:#define ICONST 42 #define FCONST 2.1828 #define CCONST 'x' #define SCONST "Hello World"
public final static native int get_ICONST(); public final static native double get_FCONST(); public final static native char get_CCONST(); public final static native String get_SCONST(); // enums and constants public final static int ICONST = get_ICONST(); public final static double FCONST = get_FCONST(); public final static char CCONST = get_CCONST(); public final static String SCONST = get_SCONST();
will produce the following Java function:int* pointer_fn(short* a, int* b, long* c);
In the above pointer_fn, any long representing a C pointer can be passed to other C functions, but any value that the pointer points to cannot be accessed from Java without using some accessor functions. Simple pointer handling is most easily handled by using the C pointer library. Here is a simple Java example using the pointer library:public final static native long pointer_fn(long jarg0, long jarg1, long jarg2);
The return value can then be read from Java and used like this:%module example %include "cpointer.i" %pointer_functions(int,intp); %inline %{ int* negate(int* number) { static int answer; answer = -*number; return &answer; } %}
When run the output will be:long intPointer = example.copy_intp(10); long negativeNumPointer = example.negate(intPointer); System.out.println("Negative of " + example.intp_value(intPointer) + " is " + example.intp_value(negativeNumPointer)); example.delete_intp(intPointer);
Pointers that are returned in one of the parameter arguments are more difficult and other workarounds are necessary. One alternative is to use the typemaps.i library which has some examples documented within the file. Some knowledge of typemaps and a browse through the Java typemaps section later on will help you grasp the concepts, but essentially if you apply the INPUT typemaps in this library you can use real values from Java where a pointer is required in C. When the pointer is an output from the C function, a Java array can be used by applying the OUTPUT typemap. The value that the pointer is pointing to is placed into the array which can be read by the calling function. A short example may help. Say we have a C function sub that returns the subtraction of the first two parameters in the third parameter:Negative of 10 is -10
Java use of the sub function:%module example %{ void sub(int *x, int *y, int *result) { *result = *x - *y; } %} %include typemaps.i extern void sub(int *INPUT, int *INPUT, int *OUTPUT);
will give the expected result:int[] r = {0}; example.sub(37,42,r); System.out.println(" 37 - 42 = " + r[0]);
These techniques are useful when handling pointers to primitive types, however, as the Java proxy classes section demonstrates, the situation is a lot better when using proxy classes.37 - 42 = -5
This will be wrapped using native Java functions, where the first argument holds the pointer to an instance of the Vector struct. Example assuming the module name is 'example':struct Vector { double x,y,z; };
These functions are then used in the resulting Java interface. For example:public class example { public final static native void set_Vector_x(long jarg0, double jarg1); public final static native double get_Vector_x(long jarg0); public final static native void set_Vector_y(long jarg0, double jarg1); public final static native double get_Vector_y(long jarg0); public final static native void set_Vector_z(long jarg0, double jarg1); public final static native double get_Vector_z(long jarg0); }
When executed will display:// v is a long holding the C pointer to a Vector that got created somehow example.set_Vector_x(v, 7.8); System.out.println("x=" + example.get_Vector_x(v));
Similar access is provided for unions and the data members of C++ classes.x=7.8
class List { public: List(); ~List(); int search(char *item); void insert(char *item); void remove(char *item); char *get(int n); int length; static void print(List *l); };
When wrapped by SWIG, will produce the following JNI C code to access the class (assuming the module is set to 'example'):
where jarg0 is the 'this' pointer in non-static functions. The JNI specification requires a C interface. The following JNI Java functions are also produced for access from Java:JNIEXPORT jlong JNICALL Java_example_new_1List(JNIEnv *jenv, jclass jcls); JNIEXPORT void JNICALL Java_example_delete_1List(JNIEnv *jenv, jclass jcls, jlong jarg0); JNIEXPORT jint JNICALL Java_example_List_1search(JNIEnv *jenv, jclass jcls, jlong jarg0, jstring jarg1); JNIEXPORT void JNICALL Java_example_List_1insert(JNIEnv *jenv, jclass jcls, jlong jarg0, jstring jarg1); JNIEXPORT void JNICALL Java_example_List_1remove(JNIEnv *jenv, jclass jcls, jlong jarg0, jstring jarg1); JNIEXPORT jstring JNICALL Java_example_List_1get(JNIEnv *jenv, jclass jcls, jlong jarg0, jint jarg1); JNIEXPORT void JNICALL Java_example_set_1List_1length(JNIEnv *jenv, jclass jcls, jlong jarg0, jint jarg1); JNIEXPORT jint JNICALL Java_example_get_1List_1length(JNIEnv *jenv, jclass jcls, jlong jarg0); JNIEXPORT void JNICALL Java_example_List_1print(JNIEnv *jenv, jclass jcls, jlong jarg0);
From Java, these functions can be used to access the C++ class:public class example { public final static native long new_List(); public final static native void delete_List(long jarg0); public final static native int List_search(long jarg0, String jarg1); public final static native void List_insert(long jarg0, String jarg1); public final static native void List_remove(long jarg0, String jarg1); public final static native String List_get(long jarg0, int jarg1); public final static native void List_length_set(long jarg0, int jarg1); public final static native int List_length_get(long jarg0); public final static native void List_print(long jarg0); }
When executed might display:long l = example.new_List(); example.List_insert(l,"Ale"); example.List_insert(l,"Stout"); example.List_insert(l,"Lager"); example.List_print(l); int len = example.get_List_length(l); System.out.println(len);
While somewhat primitive, the low-level SWIG interface provides direct and flexible access to C++ objects. As it turns out, a more elegant method of accessing structures and classes is available using proxy classes.Lager Stout Ale 3
Which happens to be what what SWIG usually outputs. When used in Java, we can use the class as follows:public class List { private long swigCPtr; protected boolean swigCMemOwn; public List(long cPtr, boolean cMemoryOwn){ swigCMemOwn = cMemoryOwn; swigCPtr = cPtr; } protected void finalize() { _delete(); } public void _delete() { if(swigCPtr != 0 && swigCMemOwn) { example.delete_List(swigCPtr); swigCMemOwn = false; } swigCPtr = 0; } public long getCPtrList(){ return swigCPtr; } public List() { this(example.new_List(), true); } public int search(String item) { return example.List_search(swigCPtr, item); } public void insert(String item) { example.List_insert(swigCPtr, item); } public void remove(String item) { example.List_remove(swigCPtr, item); } public String get(int n) { return example.List_get(swigCPtr, n); } public void setLength(int length) { example.set_List_length(swigCPtr, length); } public int getLength() { return example.get_List_length(swigCPtr); } public static void print(List l) { example.List_print(l.getCPtrList()); } }
Obviously, this is a much nicer interface than before, it only required a small amount of Java coding, it is type-safe and fits in with the Java programming paradigm.List l = new List(); l.insert("Ale"); l.insert("Stout"); l.insert("Lager"); List.print(l); int len = l.getLength(); System.out.println(len);
By writing proxy/shadow classes in Java instead of C, the classes become real Java classes that can be easily used as base-classes in an inheritance hierarchy or for other applications. Writing the proxy classes in Java also greatly simplies coding complexity as writing them in Java is much easier than trying to accomplish the same thing in C. The downside to using proxy classes over the simple interface is a slight performance degradation--a concern for some users.
This will create the following files:swig -java -proxy interface.i
The file interface_wrap.c contains the normal SWIG C JNI wrappers. The file interface.java contains the Java code corresponding to the Java native functions. The name of this file will be the same as specified by the %module directive in the SWIG interface file. These two files are produced whether or not the -proxy option is passed to SWIG. There will then be a .java file for each proxy class when -proxy is used. Note that if -c++ is passed to SWIG for wrapping C++ code, then a interface_wrap.cxx file replaces the interface_wrap.c file.interface_wrap.c interface.java plus other .java files corresponding to each proxy class
class RangeError {}; // Used for an exception class DoubleArray { private: int n; double *ptr; public: // Create a new array of fixed size DoubleArray(int size) { ptr = new double[size]; n = size; } // Destroy an array ~DoubleArray() { delete ptr; } // Return the length of the array int length() { return n; } // Get an item from the array and perform bounds checking. double getitem(int i) { if ((i >= 0) && (i < n)) return ptr[i]; else throw RangeError(); } // Set an item in the array and perform bounds checking. void setitem(int i, double val) { if ((i >= 0) && (i < n)) ptr[i] = val; else { throw RangeError(); } } };
The functions associated with this class can throw a C++ range exception for an out-of-bounds array access. We can catch the C++ exception and rethrow it as a Java exception by specifying the following in an interface file :
What the above does is define SWIG exception handlers for two types of functions; namely those that are have a void return and those that do not. Both are needed to cover all types of JNI functions. The code excerpts above are inserted into all the JNI functions. The $action call is replaced by the C/C++ code being executed by the wrapper, for example the setitem call. Another special variable, $null, is useful for typemaps that will be used in JNI functions returning all return types. See the section on Typemap variables for further explanation.%exception { try { $action } catch (RangeError) { jclass clazz = jenv->FindClass("java/lang/Exception"); jenv->ThrowNew(clazz, "Range error"); return $null; } }
The above uses the C++ JNI calling syntax as opposed to the C calling syntax and so will not compile as C. It is however possible to write JNI calls in typemaps for both C and C++ compilation. The ThrowNew() JNI function must take a class derived from java.lang.Exception. The %exception typemap above could be tailored to individual needs.
When the C++ class throws a RangeError exception, our wrapper functions will catch it, turn it into a Java exception, and allow a graceful death as opposed to having some sort of mysterious JVM crash. Since SWIG's exception handling is user-definable, we are not limited to C++ exception handling. Please see the chapter on exception handling for more details and using the exception.i library for writing language-independent exception handlers.
See the chapter on Customization Features for further examples on exceptions and how %exception can be targeted for use in a particular function.
If we use the following code:
Something similar to the following will be output when it is run:final int SIZE=5; DoubleArray arr = new DoubleArray(SIZE); for (int i=0; i<SIZE; i++) arr.setitem(i, (double)i); for (int i=0; i<SIZE+1; i++) //Note the array over bounds System.out.println(i + " " + arr.getitem(i));
0 0.0 1 1.0 2 2.0 3 3.0 4 4.0 Exception in thread "main" java.lang.Exception: Range error at example.DoubleArray_getitem(Native Method) at example.DoubleArray_getitem(Compiled Code) at DoubleArray.getitem(Compiled Code) at main.main(Compiled Code)
C/C++ type | Java type | JNI type |
bool | boolean | jboolean |
char | char | jchar |
signed char | byte | jbyte |
unsigned char | short | jshort |
short | short | jshort |
unsigned short | int | jint |
int | int | jint |
unsigned int | long | jlong |
long | int | jint |
unsigned long | long | jlong |
long long | long | jlong |
unsigned long long | java.math.BigInteger | jobject |
float | float | jfloat |
double | double | jdouble |
char* | String | jstring |
void | void | void |
The non proxy access from Java is shown below, where the first parameter, ptr, is a long containing the pointer to an object of type AClass:void AClass::func(int a, int* b, SomeClass c, SomeClass* d, SomeClass& e, SomeClass f[10]);
The Java proxy class, AClass, will contain the following function:public final static native void AClass_func(long ptr, int a, long b, long c, long d, long e, long[] f);
public void func(int a, long b, SomeClass c, SomeClass d, SomeClass e, SomeClass f[]) {...}
The mappings for C int and C long are appropriate for 32 bit applications which are used in the current 32 bit JVMs. There is no perfect mapping between Java and C as Java doesn't support all the unsigned C data types. However, the mappings allow the full range of C values from Java.
For future 64 bit JVMs you may have to change the C long, but probably not C int mappings. Mappings will be system dependent, for example long will need remapping on Unix LP64 systems (long, pointer 64 bits, int 32 bits), but not on Microsoft 64 bit Windows which will be using a P64 IL32 (pointer 64 bits and int, long 32 bits) model. This may be automated in a future version of SWIG. Note that the Java write once run anywhere philosophy holds true for all pure Java code when moving to a 64 bit JVM. Unfortunately it won't of course hold true for JNI code.
%module example %typemap(in) int { $1 = $input; printf("Received an integer : %d\n", $1); } extern int fact(int n);
Typemaps require a method name, datatype, and conversion code. The "in" method in this example refers to an input argument of a function. The datatype `int' tells SWIG that we are remapping integers. The supplied code is used to convert from a jint to the corresponding C datatype, int. Within the supporting C code, the variable $input contains the Java data (the JNI jint in this case) and $1 contains the destination of a conversion.
When this example is compiled into a Java module, it can be used as follows:
and the output will be:System.out.println(example.fact(6));
Received an integer : 6 720
A full discussion of typemaps can be found in the SWIG users reference section on typemaps. We will primarily be concerned with Java typemaps here.
Typemap | Description |
typemap(jni) | JNI types. These provide the default mapping of types from C to JNI. |
typemap(jtype) | Java types. These provide the default mapping of types from C to Java when used in the Java module class. |
typemap(jstype) | Java proxy class types. These provide the default mapping of types from C to Java when used in Java proxy classes. |
The default code generated by SWIG for the Java module comes from the typemaps in the java.swg library file.
There are other typemaps in the Java library which could be used.
These are listed below:
C Type | Typemap | File | Kind | Java Type | Function |
char * | BYTE | various.i | input
output |
byte[] | Java byte array is converted to char array which is released afterwards |
char ** | STRING_IN | various.i | input | String[] | \0 terminated array of \0 terminated strings
the array is malloc-ed and released afterwards |
STRING_OUT | various.i | output | String[] | &char*
the argument is the address of an '\0' terminated string |
|
STRING_RET | various.i | return | String[] | \0 terminated array of \0 terminated strings
the array is not free-ed. |
|
primitive type pointers | INPUT | typemaps.i | input | Java basic types | Allows values to be used for C functions taking pointers for data input. |
primitive type pointers | OUTPUT | typemaps.i | output | Java basic type arrays | Allows values held within an array to be used for C functions taking pointers for data output. |
primitive type pointers | INOUT | typemaps.i | input output |
Java basic type arrays | Allows values held within an array to be used for C functions taking pointers for data input and output. |
string wstring |
[unnamed] | std_string.i | input ouput |
String | Use for std::string mapping to Java String. |
If a %typemap(in) is written, a %typemap(freearg) and %typemap(argout) may also need to be written. This is because some types have a default 'freearg' and/or 'argout' typemap which may need overriding. The 'freearg' typemap sometimes releases memory allocated by the 'in' typemap. The 'argout' typemap sometimes sets values in function parameters which are passed by reference in Java. Take a look at the default typemaps in java.swg.
The Java module uses a few additional special variables:
$javaclassname
Only in jstype typemaps.
$javaclassname is similar to $1_basetype, except when applied to unions/structs/classes.
Here the type name is used if it has been wrapped by SWIG otherwise a Java long is used.
Used primarily to get the Java classname of a wrapped union/struct/class.
For example, $javaclassname is replaced by 'Foo' when the type is 'struct Foo'.
$null
Used in input typemaps to return early from JNI functions that have either void or a non-void return type. Example:
If the typemap gets put into a function with void as return, $null will expand to nothing:%typemap(check) int * %{ if (error) { SWIG_exception(SWIG_IndexError, "Array element error"); return $null; } %}
otherwise $null expands to NULLvoid jni_fn(...) { if (error) { SWIG_exception(SWIG_IndexError, "Array element error"); return ; } ... }
jobject jni_fn(...) { if (error) { SWIG_exception(SWIG_IndexError, "Array element error"); return NULL; } ... }
whereas C++ code compilation of the same function call is a member function call using a class pointer likeconst jclass clazz = (*jenv)->FindClass(jenv, "java/lang/String");
To enable typemaps to be used for either C or C++ compilation, a set of JCALLx macros have been defined in Lib/java/javahead. swg, where x is the number of arguments in the C++ version of the JNI call. The above JNI calls would be written in a typemap like thisconst jclass clazz = jenv->FindClass("java/lang/String");
Note that the SWIG preprocessor expands these into the appropriate C or C++ JNI calling convention. The C calling convention is emitted by default and the C++ calling convention is emitted when using the -c++ SWIG commandline option. If you do not intend your code to be compiled under both C and C++ then your typemaps can use the appropriate JNI calling convention and need not use the JCALLx macros.const jclass clazz = JCALL1(FindClass, jenv, "java/lang/String");
In this example, two typemaps are applied to the char ** datatype. However, the second typemap will only be applied to arguments named `argv'. A named typemap will always override an unnamed typemap.%module foo // This typemap will be applied to all char ** function arguments %typemap(in) char ** { ... } // This typemap is applied only to char ** arguments named `argv' %typemap(in) char **argv { ... }
Due to the name-based nature of typemaps, it is important to note that typemaps are independent of typedef declarations. For example :
To get around this problem, the %apply directive can be used as follows :%typemap(in) double { ... get a double ... } void foo(double); // Uses the above typemap typedef double Real; void bar(Real); // Does not use the above typemap (double != Real)
%typemap(in) double { ... get a double ... } void foo(double); typedef double Real; // Uses typemap %apply double { Real }; // Applies all "double" typemaps to Real. void bar(Real); // Now uses the same typemap.
Note that the 'C' JNI calling convention is used. Checking for any thrown exceptions after JNI function calls has been omitted. When this module is compiled, our wrapped C functions can now be used by the following Java program:%module example /* This tells SWIG to treat char ** as a special case when used as a parameter in a function call */ %typemap(in) char** (jint size) { int i = 0; size = (*jenv)->GetArrayLength(jenv, $input); $1 = (char **) malloc((size+1)*sizeof(char *)); /* make a copy of each string */ for (i = 0; i<size; i++) { jstring j_string = (jstring)(*jenv)->GetObjectArrayElement(jenv, $input, i); const char* c_string = (*jenv)->GetStringUTFChars(jenv, j_string, 0); $1[i] = malloc(strlen((c_string)+1)*sizeof(const char*)); strcpy($1[i], c_string); (*jenv)->ReleaseStringUTFChars(jenv, j_string, c_string); (*jenv)->DeleteLocalRef(jenv, j_string); } $1[i] = 0; } /* This cleans up the memory we malloc'd before the function call */ %typemap(freearg) char** { int i; for (i=0; i<size-1; i++) free($1[i]); free($1); } /* This allows a C function to return a char ** as a Java String array */ %typemap(out) char** { int i; int len=0; jstring temp_string; const jclass clazz = (*jenv)->FindClass(jenv, "java/lang/String"); while ($1[len]) len++; jresult = (*jenv)->NewObjectArray(jenv, len, clazz, NULL); /* exception checking omitted */ for (i=0; i<len; i++) { temp_string = (*jenv)->NewStringUTF(jenv, *result++); (*jenv)->SetObjectArrayElement(jenv, jresult, i, temp_string); (*jenv)->DeleteLocalRef(jenv, temp_string); } } /* This tells SWIG what the matching JNI type for the Java type is */ %typemap(jni) char** "jobjectArray" /* This tells SWIG what Java type to use */ %typemap(jtype) char** "String[]" %typemap(jstype) char** "String[]" /* Now a few test functions */ %inline %{ int print_args(char **argv) { int i = 0; while (argv[i]) { printf("argv[%d] = %s\n", i, argv[i]); i++; } return i; } char **get_args() { static char *values[] = { "Dave", "Mike", "Susan", "John", "Michelle", 0}; return &values[0]; } %}
When compiled and run we get:// File main.java public class main { static { try { System.loadLibrary("example"); } catch (UnsatisfiedLinkError e) { System.err.println("Native code library failed to load. " + e); System.exit(1); } } public static void main(String argv[]) { String animals[] = {"Cat","Dog","Cow","Goat"}; example.print_args(animals); String args[] = example.get_args(); for (int i=0; i<args.length; i++) System.out.println(i + ":" + args[i]); } }
Our type-mapping makes the Java interface to these functions more natural and easy to use.$ java main argv[0] = Cat argv[1] = Dog argv[2] = Cow argv[3] = Goat 0:Dave 1:Mike 2:Susan 3:John 4:Michelle
Now we are going to outline an alternative approach to using arrays for C pointers. The INOUT typemap uses a double[] array for receiving and returning the double* parameters. In this approach we are able to use a Java class myDouble instead of double[] arrays where the C pointer double* is required.
If we define a structure 'MyDouble' containing a double and use some typemaps we can solve this problem, for example we could put the following through SWIG:/* Returns a status value and two values in out1 and out2 */ int spam(double a, double b, double *out1, double *out2);
Note that the C++ JNI calling convention has been used this time and so must be compiled as C++ and the -c++ commandline must be passed to SWIG. Also this will only work with proxy classes enabled (-proxy commandline option) as the MyDouble proxy class contains the member variable 'swigCPtr' which we need in the 'in' typemap. JNI error checking has been omitted for clarity.%module example %{ /* Returns a status value and two values in out1 and out2 */ int spam(double a, double b, double *out1, double *out2) { int status = 1; *out1 = a*10.0; *out2 = b*100.0; return status; }; %} /* Define a new structure to use instead of double* */ %inline %{ typedef struct { double value; } MyDouble; %} /* This typemap will make any double* function parameters with name 'OutValue' take an argument of MyDouble instead of double*. Requires -proxy commandline option. This will allow the calling function to read the double* value after returning from the function. */ %typemap(in) double *OutValue { jclass clazz = jenv->FindClass("MyDouble"); jfieldID fid = jenv->GetFieldID(clazz, "swigCPtr", "J"); jlong cPtr = jenv->GetLongField($input, fid); MyDouble* pMyDouble = NULL; *(MyDouble*)&pMyDouble = *(MyDouble*)&cPtr; $1 = &pMyDouble->value; } /* This tells SWIG what Java type to use */ %typemap(jtype) double* OutValue "MyDouble" %typemap(jstype) double* OutValue "MyDouble" /* This tells SWIG what the matching JNI type for the Java type is */ %typemap(jni) double* OutValue "jobject" /* Now we apply the typemap to the named variables */ %apply double* OutValue { double *out1, double* out2 }; int spam(double a, double b, double *out1, double *out2);
What the typemaps do are make the named double* function parameters use our new MyDouble wrapper structure. The 'in' typemap takes this structure, gets the C++ pointer to it, is then able to get the 'double value' member variable to pass to the C++ spam function. In Java, when the function returns, we use the SWIG created getValue() function to get the output value. The following Java program demonstrates this:
When compiled and run we get:// File: main.java public class main { static { try { System.loadLibrary("example"); } catch (UnsatisfiedLinkError e) { System.err.println("Native code library failed to load. " + e); System.exit(1); } } public static void main(String argv[]) { MyDouble out1 = new MyDouble(); MyDouble out2 = new MyDouble(); int ret = example.spam(1.2, 3.4, out1, out2); System.out.println(ret + " " + out1.getValue() + " " + out2.getValue()); } }
$ java main 1 12.0 340.0
By default, the Java module supplies the memberin typemap in the java_arrays.i file to set array members. It is generic, but not particularly efficient as it copies one array member at a time. You may want to override it for the above Data struct as follows:#define LEN 5 typedef struct { int numbers[LEN]; } Data;
Whenever an int[LEN] type is encountered in a structure or class, this typemap provides a safe mechanism for setting its value. An alternative implementation might choose to print an error message if the Java supplied array was too long to fit into the field.%typemap(memberin) int[LEN] { /* Copy at most LEN characters into $1 */ memcpy($1,$input,sizeof(int)*LEN); }
It should be noted that the [LEN] array size is attached to the typemap. A datatype involving some other kind of array would not be affected. However, you can write a typemap to match any sized array using the ANY keyword as follows :
%typemap(memberin) int [ANY] { memcpy($1,$input,sizeof(int)*$1_dim0); }
During code generation, $1_dim0 will be filled in with the real array dimension.
As mentioned, pointers are stored in a Java long, which is a 64 bit number. However most JVMs are 32 bit applications so any JNI code must also be compiled as 32 bit. This means that the pointers in JNI code are also 32 bits. What happens for various reasons is on big endian machines the pointer is stored in the high order 4bytes, whereas on little endian machines the pointer is stored in the low order 4bytes. As a result, care must be taken if you intend to manipulate the pointer directly from Java. This can of course can be changed with judicious use of typemaps, but normally you needn't worry about any of this unless you want to modify pointers within Java code.
By now you hopefully have the idea that typemaps are a powerful mechanism for building more specialized applications. While writing typemaps can be technical, many have already been written for you. See the Typemaps chapter for more information about using library files.
%module example %inline %{ class Simple { public: Simple() {}; ~Simple() {}; }; %}
The SWIG generated class in file Simple.java looks something like the following:
// File Simple.java public class Simple { private long swigCPtr; protected boolean swigCMemOwn; public Simple(long cPtr, boolean cMemoryOwn){ swigCMemOwn = cMemoryOwn; swigCPtr = cPtr; } protected void finalize() { _delete(); } public void _delete() { if(swigCPtr != 0 && swigCMemOwn) { example.delete_Simple(swigCPtr); swigCMemOwn = false; } swigCPtr = 0; } public long getCPtrSimple(){ return swigCPtr; } public Simple() { this(example.new_Simple(), true); } }
The default object ownership falls into 2 cases:
It allows one to override the above default swigCPtr and swigCMemOwn values on construction.public Simple(long cPtr, boolean cMemoryOwn){ swigCMemOwn = cMemoryOwn; swigCPtr = cPtr; }
The finalize() method is generated by default, but it can be turned off using the -nofinalize commandline option. It calls the _delete() method which calls the C++ destructor only if the Java object owns the C++ memory. If there is no C++ default constructor, a default constructor is required by Java and so a protected constructor is generated as follows:
Note that when using C++ the compiler generates a default constructor and destructor for you if none exist. SWIG attempts to mirror this behaviour. It is possible to turn off default constructor/destructor generation through the use of the %nodefault directive, but is unlikely to work very well with proxy classes. Note that SWIG currently does not support method overloading and thus constructor overloading, but this is likely to change in a future release.protected Simple() { swigCPtr = 0; _cMemOwn = false; }
The class can be used as follows to read and write to the variables:class Simple { public: Simple() {}; ~Simple() {}; int Number; static int StaticNumber; };
Note that the C++ static member variable is mapped using Java static getters and setters.Simple simp = new Simple(); simp.setNumber(10); int number = simp.getNumber(); Simple.setStaticNumber(10); number = Simple.getStaticNumber();
By default in the simple SWIG interface, the function addv will operate on Vector pointers (a Java long), not Java classes:%module example struct Vector { Vector(); ~Vector(); double x,y,z; static Vector addv(Vector a, Vector b); };
However, when using proxy classes, the Java SWIG module is smart enough to know that Vector has been wrapped into a Java class so it will create the following proxy function for the addv() function.// Member function in class example (SWIG's simple interface) public final static native long Vector_addv(long jarg0, long jarg1);
Function arguments are modified to pick up the "this" pointer from a Java Vector object. The return value is a pointer to the result which has been allocated by malloc or new (this behavior is described in the chapter on SWIG basics), so we simply create a new Vector class with the return value. Since the result involved an implicit malloc, we set the ownership to true indicating that the result is to be owned by Java and that it should be deleted when the Java object is deleted. As a result, operations like this are perfectly legal and result in no memory leaks:// Member function in class Vector (the proxy class) public static Vector addv(Vector a, Vector b) { return new Vector(example.Vector_addv(a.getCPtrVector(), b.getCPtrVector()), true); }
Vector v = Vector.addv(Vector.addv(Vector.addv(Vector.addv(a,b),c),d),e);
By default in the simple SWIG interface, the function cross_product will also operate on Vector pointers (a Java long):%module example struct Vector { Vector(); ~Vector(); double x,y,z; static Vector addv(Vector a, Vector b); static Vector *cross_product(Vector *v1, Vector *v2); };
When using proxy classes, the Java SWIG module still allows us to use a Vector proper:// Member function in class example (SWIG's simple interface) public final static native long Vector_cross_product(long jarg0, long jarg1);
The proxy function gets the pointer for us from the Vector class. Note that the return value is a Vector whose memory ownership is set to false indicating that the memory is not owned by Java. The following section discusses this further.// Member function in class Vector (the proxy class) public static Vector cross_product(Vector v1, Vector v2) { return new Vector(example.Vector_cross_product(v1.getCPtrVector(), v2.getCPtrVector()), false); }
If say, the cross_product() function could take a NULL pointer and you wanted to pass one in, a NULL Vector proxy class would need creating first:
This can be passed in to any function taking a Vector*.Vector nullVector = new Vector(0, false);
An important observation to note when using proxy classes is the differences in wrapping pointers to complex datatypes and pointers to primitive types. Pointers to complex data types are wrapped using a Java class, such as Vector for Vector*. Pointers to primitive types are wrapped in the same manner as the simple interface, that is a Java long for short*, int* etc.
When the value is returned to Java, we want Java to assume ownership as the memory has been created on the heap. However, SWIG has no way of knowing that it should take ownership, so by default it does not. The memory has to be deleted after calling the cross_product function:Vector *Vector::cross_product(Vector *v1, Vector *v2) { Vector *result = new Vector(); result = ... compute cross product ... return result; }
Unfortunately, this is ugly, is likely to be forgotten and it doesn't work if we use the result as a temporary value :Vector a = new Vector(); Vector b = new Vector(); // ... populate a and b ... Vector c = Vector.cross_product(a, b); // clean up the memory allocated by cross_product example.delete_Vector(c.getCPtrVector());
However, you can provide a hint to SWIG when working with such a function as shown :Vector w = Vector.addv(Vector.cross_product(a,b),c); // Results in a memory leak
The %new directive provides a hint that the function is returning a new object. The Java module will assign proper ownership of the object when this is used. This can be seen as this time it uses true in the constructor:// C/C++ Function returning a new object struct Vector { ... %new static Vector *cross_product(Vector *v1, Vector *v2); ... };
// Member function in class Vector (the proxy class) public static Vector cross_product(Vector v1, Vector v2) { return new Vector(example.Vector_cross_product(v1.getCPtrVector(), v2.getCPtrVector()), true); }
The dummy class consists entirely of static member functions. Note that static takes on the C++ meaning of static even when used in C code. Also take note of the two different ways that global_subv can be wrapped into Globals. Access to the global function global_subv is then much neater:%module example %inline %{ struct Vector { Vector() {}; ~Vector() {}; double x,y,z; static Vector addv(Vector a, Vector b); }; // Global function and variable Vector global_subv(Vector a, Vector b); Vector global_vec; // Global function and variable wrapped into this structure struct Globals { static Vector sub1(Vector a, Vector b) { return global_subv(a, b); }; static void setGlobal_vec(Vector v) { global_vec = v; }; static Vector getGlobal_vec(void) { return global_vec; }; }; %} // Alternative way to wrap global functions into a structure %extend Globals { static Vector sub2(Vector a, Vector b) { return global_subv(a, b); }
This is one area where the Java module needs improving in the future so that all global functions are for instance automatically accessible through a proxy class.Vector a = new Vector(); Vector b = new Vector(); // ... setup a and b ... // Access to global function which has been wrapped into the Globals proxy class Vector c1 = Globals.sub1(a,b); Vector c2 = Globals.sub2(a,b); // Access to global function using simple interface Vector c3 = new Vector(example.global_subv(a.getCPtrVector(), b.getCPtrVector()), true);
%module example %inline %{ struct Vector { double x,y,z; static Vector addv(Vector a, Vector b); }; typedef struct { Vector r; Vector v; Vector f; int type; } Particle; %}
In this case you will be able to read and write to members as follows :
Nested structures such as the following are also supported by SWIG. These types of structures tend to arise frequently in database and information processing applications.Vector v1 = new Vector(); Vector v2 = new Vector(); // ... populate v1 and v2 ... Particle p = new Particle(); p.getR().setX(0.0); p.getR().setY(-1.5); p.getR().setZ(2.0); p.setV( Vector.addv(v1, v2) );
Access is provided like this:typedef struct { unsigned int dataType; union { int intval; double doubleval; char *charval; void *ptrvalue; long longval; struct { int i; double f; void *v; char name[32]; } v; } u; } ValueStruct;
To support the embedded structure definitions, SWIG has to extract the internal structure definitions and use them to create new Java classes. In this example, the following proxy classes are created:ValueStruct v = new ValueStruct(); // ... populate ValueStruct somehow ... long dataType = v.getDataType(); int intval = v.getU().getIntval(); double f = v.getU().getV().getF();
//Class corresponding to union u member ValueStruct_u u = v.getU(); //Class corresponding to struct v member of union u ValueStruct_u_v uv = v.getU().getV();
The names of the new classes are formed by appending the member names of each embedded structure.
The base class Shape is generated much like any other proxy class seen so far:class Shape { double x, y; public: Shape(); virtual ~Shape(); void move(double dx, double dy); virtual double area(); }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) { }; virtual double area(); };
The Circle class extends Shape mirroring the C++ class inheritance hierarchy.// File Shape.java public class Shape { private long swigCPtr; protected boolean swigCMemOwn; public Shape(long cPtr, boolean cMemoryOwn){ swigCMemOwn = cMemoryOwn; swigCPtr = cPtr; } protected Shape() { this(0, false); } protected void finalize() { _delete(); } public void _delete() { if(swigCPtr != 0 && swigCMemOwn) { example.delete_Shape(swigCPtr); swigCMemOwn = false; } swigCPtr = 0; } public long getCPtrShape(){ return swigCPtr; } public void move(double dx, double dy) { example.Shape_move(swigCPtr, dx, dy); } public double area() { return example.Shape_area(swigCPtr); } }
Note the memory ownership is controlled by the base class. However each class in the inheritance hierarchy has its own pointer value which is obtained during construction. The CircleToShape() call converts the pointer from a Circle* to a Shape* as C++ compilers are free to implement pointers in the inheritance hierarchy with different values. The getCPtrCircle() and getCPtrShape() functions can be used to obtain a correctly cast pointer to that particular class.// File Circle.java public class Circle extends Shape{ private long swigCPtr; public Circle(long cPtr, boolean cMemoryOwn){ super(example.CircleToShape(cPtr), cMemoryOwn); swigCPtr = cPtr; } protected Circle() { this(0, false); } protected void finalize() { _delete(); } public void _delete() { if(swigCPtr != 0 && swigCMemOwn) { example.delete_Circle(swigCPtr); swigCMemOwn = false; super._delete(); } swigCPtr = 0; } public long getCPtrCircle(){ return swigCPtr; } public Circle(double r) { this(example.new_Circle(r), true); } public double area() { return example.Circle_area(swigCPtr); } }
It is of course possible to extend Shape using your own Java classes. If say Circle is provided by the C++ code, you could for example add in a pure Java class Rectangle derived from Shape. There is a caveat and that is any C++ code will not know about your Java class Rectangle so this type of derivation is restricted.
Note that Java does not support multiple inheritance so any multiple inheritance in the C++ code is not going to work. A warning is given when multiple inheritance is detected and only the first base class is used.
_delete()
and finalize()
methods.
The finalize()
method calls _delete()
which frees any SWIG malloced C memory for wrapped structs or deletes any SWIG wrapped classes created on the heap, which in turn calls the class' destructor.
The idea is for _delete()
to be called when you have finished with the C/C++ object.
Ideally you need not call _delete()
, but rather leave it to the garbage collector to call it from the finalizer.
The unfortunate thing is that Sun, in their wisdom, do not guarantee that the finalizers will be called.
When a program exits, the garbage collector does not always call the finalizers.
Depending on what the finalizers do and which operating system you use, this may or may not be a problem.
If the _delete()
call into JNI code is just for memory handling, there is not a problem when run on Windows and Unix.
Say your JNI code creates memory on the heap which your finalizers will clean up, the finalizers may or may not be called before the program exits.
In Windows and Unix all memory that a process uses is returned to the system, so this isn't a problem.
This is not the case in some operating systems like vxWorks.
If however, your finalizer calls into JNI code invoking the C++ destructor which in turn releases a TCP/IP socket for example, there is no guarantee that it will be released.
Note that the garbage collector will eventually run, so long running programs will have their unreferenced object's finalizers called.
Some not so ideal solutions are:
System.runFinalizersOnExit(true)
or Runtime.getRuntime().runFinalizersOnExit(true)
to ensure the finalizers are called before the program exits. The catch is that this is a deprecated function call as the documenation says:
This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.In many cases you will be lucky and find that it works, but it is not to be advocated. Have a look at Sun's Java web site and search for
runFinalizersOnExit
.
addShutdownHook()
, was introduced which is guaranteed to be called when your program exits.
You can encourage the garbage collector to call the finalizers, for example, add this static block to the class that has the main()
function:
Although this usually works, the documentation doesn't guarantee thatstatic { Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { System.gc(); System.runFinalization(); } } ); }
runFinalization()
will actually call the finalizers.
As the the shutdown hook is guaranteed you could also make a JNI call to clean up any resources that are being tracked by the C/C++ code.
_delete()
function manually.
As a suggestion it may be a good idea to set the object to null so that should the object be inadvertantly used again a Java null pointer exception is thrown, the alternative would crash the JVM by using a null C pointer.
For example given a SWIG generated class A:
The SWIG generated code ensures that the memory is not deleted twice, in the event the finalizers get called in addition to the manualA myA = new A(); // use myA ... myA._delete(); // any use of myA here would crash the JVM myA=null; // any use of myA here would cause a Java null pointer exception to be thrown
_delete()
call.
Java classes without any finalizers generally speed up code execution as there is less for the garbage collector to do. Finalizer generation can be turned off with the -nofinalize command line option. However, you will have to be careful about memory management and make sure that you code in a call to the _delete() member function to free up the C/C++ object memory and which will include the destructor call for C++.
If performance is really critical you can use the low-level interface which eliminates all of the overhead of going through the proxy classes (at the expense of coding simplicity).
/* TestStruct.i */ #ifdef SWIG %pragma(java) modulecode=%{ /*This code gets added to the module class*/ %} %pragma(java) modulecode=%{ /*This code gets added to the module class*/ %} %pragma(java) allshadowcode=%{ /*This code gets added to every shadow class*/ %} #endif typedef struct TestStruct { #ifdef SWIG %pragma(java) shadowcode=%{ /*This code gets added to the TestStruct shadow class only*/ %} #endif int myInt; } TestStruct;
%pragma(java) modulecode= " public void sayHello() { System.out.println(\"Hello\"); } " %pragma(java) modulecode=%{ public void sayHello() { System.out.println("Hello"); } %}
Pragma | Description | Example |
modulebase | Specifies a base class for the Java module class. | %pragma(java) modulebase="BaseClass" |
shadowbase | Specifies a base class for the Java shadow class. | %pragma(java) shadowbase="BaseClass" |
allshadowbase | Specifies a base class for all Java shadow classes. | %pragma(java) allshadowbase="BaseClass" |
modulecode | Adds code to the Java module class. | %pragma(java) modulecode=%{/*module code*/%} |
shadowcode | Adds code to the Java shadow class. See the JavaDoc section below about using this pragma for JavaDoc comments. | %pragma(java) shadowcode=%{/*shadow code*/%} |
allshadowcode | Adds code to all Java classes. | %pragma(java) allshadowcode=%{/*all shadow code*/%} |
moduleclassmodifiers | Overrides the default Java module class modifiers. The default is public. | %pragma(java) moduleclassmodifiers="public final" |
shadowclassmodifiers | Overrides the default Java shadow class modifiers. The default is public. Also overrides allshadowclassmodifiers if present. | %pragma(java) shadowclassmodifiers="public final" |
allshadowclassmodifiers | Overrides the default modifiers for all Java classes. The default is public. | %pragma(java) allshadowclassmodifiers="public final" |
moduleimport | Adds an import statement to the Java module class file. | %pragma(java) moduleimport="java.lang.*" |
shadowimport | Adds an import statement to the Java shadow class file. Adds to any imports specified in allshadowimport. | %pragma(java) shadowimport="java.lang.*" |
allshadowimport | Adds an import statement to all Java shadow class files. | %pragma(java) allshadowimport="java.lang.*" |
moduleinterface | Specifies an interface which the Java module output class implements. Can be used multiple times as Java supports multiple interfaces. | %pragma(java) moduleinterface="SomeInterface" |
shadowinterface | Specifies an interface which the Java shadow class implements. Can be used multiple times as Java supports multiple interfaces. Adds to any interfaces specified in allshadowinterface. | %pragma(java) shadowinterface="SomeInterface" |
allshadowinterface | Specifies an interface which all Java shadow classes implement. Can be used multiple times as Java supports multiple interfaces. | %pragma(java) allshadowinterface="SomeInterface" |
modulemethodmodifiers | Overrides the native default method modifiers for the module class. The default is public final static. | %pragma(java) modulemethodmodifiers="protected final static synchronized" |
%module example %{ #include "MyClass.h" %} %include "MyClass.h" // Use a shadow pragma without modifying the original code in MyClass.h %extend MyClass{ %pragma(java) shadowcode="/* Some extra shadow code for MyClass */" }
System.loadLibrary("name")
.
This can fail and it can be due to a number of reasons.
loadLibrary
function.
The text passed to the loadLibrary
function must not include the the extension name in the text, that is .dll or .so.
The text must be name and not libname for all platforms. On Windows the native library must then be called name.dll and on Unix it must be called libname.so.
If you are debugging using java -debug
, then the native library must be called name_g.dll on Windows and libname_g.so on Unix.
Another common reason for the native library not loading is because it is not in your path. On Unix make sure that your LD_LIBRARY_PATH contains the path to the native library. On Windows make sure the path environment variable contains the path to the native library. SWIG code usually works if you have LD_LIBRARY_PATH set to '.' (or no modification to path in Windows).
The native library will also not load if there are any unresolved symbols in the compiled C/C++ code. Unresolved symbols will be described if you use the -verbose:jni commandline switch when running Java.
Ensure that you are using the correct C/C++ compiler and linker combination and options for successful native library loading. The Examples/Makefile must have these set up correctly for your system. The SWIG installation package makes a best attempt at getting these correct but does not get it right 100% of the time.
Linking problems used to occur when there were underscores in the module name or package name. This was fixed in SWIG 1.3.7.
If you don't want SWIG to wrap your JNI function as you have written the Java native function declaration in addition to the JNI function, simply use the %ignore directive.
Alternatively you may want SWIG to help out and do some work by using the %native directive, for example:
No C/C++ code will be generated and the Java_modulename_HandRolled function will be unmodified and accessible using the SWIG generated Java native function call which will look something like this:%typemap (jtype) SomeCType "SomeJavaClass"; %native (HandRolledJavaName) int HandRolledCName(long, char*, SomeCType); %{ JNIEXPORT jint JNICALL Java_modulename_HandRolled ( JNIEnv *jenv, jclass jcls, jint net, jstring path, jobject SomeJavaClass) { /* implementation */ }
What is happening here is the %native directive is telling SWIG to generate the module Java native method declaration, but not the JNI C code for a (possibly non-existent) C function called HandRolledCName. To accomplish this SWIG needs to be told about the mapping of (possibly non-existent) C types to Java types, either using the built in mapping (char* -> String) or the supplied one using the jtype typemap (SomeCType -> SomeJavaClass). This is only really useful if you want to mix your own JNI code and the SWIG generated code into one C/C++ file or mix your own JNI function calls into a SWIG generated Java class.public final static native int HandRolledJavaName(int jarg1, String jarg2, SomeJavaClass jarg3);