14 SWIG and Java

This chapter describes SWIG's support of Java. Java is one of the latest modules to be added to SWIG. The other SWIG modules are primarily scripting languages. Using Java has the advantage over scripting languages of being type safe. The 100% Pure Java effort is a commendable concept however, in the real world programmers either need to re-use their existing code or in some situations want to take advantage of Java but are forced into using some native (C/C++) code. With this Java extension to SWIG it is very easy to plumb in existing C/C++ code for access from Java, as SWIG writes the Java Native Interface (JNI) code for you. It is different to using the 'javah' tool as SWIG will wrap existing C/C++ code, whereas javah takes Java functions and creates C/C++ function prototypes.

14.1 Preliminaries

SWIG 1.1 works with JDK 1.1 and higher. Given the choice, you should use the latest version of Sun's JDK. The SWIG Java module is known to work on Solaris, the various flavours of Windows including cygwin and Linux using Sun's JDK. It is also known to work on vxWorks using their PJava 3.1. The Kaffe JVM is known to give a few problems and at the time of writing was not a fully fledged JVM with full JNI support. The best way to determine whether your combination of operating system and JDK will work is to test the examples and test-suite that comes with SWIG. Run the make check from the SWIG root directory after installing SWIG.

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.

14.1.1 Running SWIG

The basics of getting a SWIG Java module up and running can be seen from one of SWIG's example Makefiles, but is also described here. To build a Java module, run SWIG using the -java option. Enabling proxy classes -proxy is also recommended:

%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.

14.1.2 Additional Commandline Options

The following table list the additional commandline options available for the Java module. They can also be seen by using:
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

Their use will become clearer by the time you have finished reading this section on SWIG and Java.

14.1.3 Getting the right header files

In order to compile, you need to locate the "jni.h" and "md.h" header files which are part of the JDK. They are usually in directories like this:

/usr/java/include
/usr/java/include/<operating_system>

The exact location may vary on your machine, but the above locations are typical.

14.1.4 Compiling a dynamic module

The JNI code exists in a dynamic module or shared object and gets loaded by the JVM. To build a shared object file, you need to compile your module in a manner similar to the following (shown for Solaris):

$ 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

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.

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.

14.1.5 Using your module

To use your module in Java, simply use Java's System.loadLibrary method in a Java class:

// main.java

public class main {
  static {
    System.loadLibrary("example");
  }

  public static void main(String argv[]) {
    System.out.println(example.fact(4));
  }
}
Compile all the Java files and run:
$ javac *.java
$ java main
24
$

14.1.6 Compilation problems and compiling with C++

For the most part, compiling a Java module is straightforward, but there are a number of potential problems :

14.2 Building Java Extensions under Windows

Building a SWIG extension to Java under Windows is roughly similar to the process used with Unix. You will want to produce a DLL that can be loaded by the Java Virtual Machine. This section covers the process of using SWIG with Microsoft Visual C++ 6 although the procedure may be similar with other compilers. In order to build extensions, you will need to have a JDK installed on your machine in order to read the JNI header files.

14.2.1 Running SWIG from Developer Studio

If you are developing your application within Microsoft developer studio, SWIG can be invoked as a custom build option. The process roughly follows these steps:

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.

14.2.2 Using NMAKE

Alternatively, SWIG extensions can be built by writing a Makefile for NMAKE. Make sure the environment variables for MSVC++ are available and the MSVC++ tools are in your path. Now, just write a short Makefile like this :

# 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.

14.3 The low-level Java/C interface

The SWIG Java module is based upon a basic low-level interface that provides access to C functions, variables, constants, and C++ classes. This low-level interface is not the recommended way to use SWIG with Java; proxy classes are the recommended way. This low-level interface is used by the proxy class interface so it is used behind the scenes.

14.3.1 Modules and the module class

The SWIG %module directive specifies the name of the Java module. If you specified `%module example', then everything found in a SWIG interface file will be contained within the Java module class which in this case will be called `example'. In other words the module class contains all the C/C++ functions and accessor functions to variables that have been wrapped by SWIG. Make sure you don't use the same name as a Java keyword for your module name else the Java output will not compile.

14.3.2 Functions

C/C++ functions are mapped directly into a matching method in a Java class named after the module name. For example :

%module example
extern int fact(int n);
Will produce the following JNI C function:
JNIEXPORT jint JNICALL Java_example_fact(JNIEnv *jenv, jclass jcls, jint jarg0) {
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:
public class example  {
  public final static native int fact(int jarg0);
}
It can be used as follows from Java:

System.out.println(example.fact(4));

14.3.3 Variable Linking

SWIG provides access to C/C++ global variables through the class named after the module name, in other words all global variables are wrapped into the module class. Java does not allow the overriding of the dot operator so all variables are accessed through getters and setters. For example:

/* SWIG interface file with global variables */
%module example
...
extern int My_variable;
...

Now in Java :

// 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);
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'.

14.3.4 Enums

SWIG will wrap enumerations. They appear as public final static Java variables. The Java enum names match the C/C++ enum names. For example, the following C enum:

enum color { RED, BLUE, GREEN };
will be wrapped with the following Java:
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();
}

14.3.5 Constants

C/C++ constants (from a #define or the %constant SWIG directive) are wrapped by public final static Java variables and are initialised using a native JNI function call. These constants are given the same name as the corresponding C constant. For example, the following C:

#define    ICONST      42
#define    FCONST      2.1828
#define    CCONST      'x'
#define    SCONST      "Hello World"
will be wrapped with the following Java:
  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();

14.3.6 Pointers

All C pointers are treated as Java longs by default in the low-level interface. For example:

int* pointer_fn(short* a, int* b, long* c);
will produce the following Java function:
public final static native long pointer_fn(long jarg0, long jarg1, long jarg2);
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:
%module example
%include "cpointer.i"
%pointer_functions(int,intp);

%inline %{
int* negate(int* number) {
    static int answer;
    answer = -*number;
    return &answer;
}
%}

The return value can then be read from Java and used like this:
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);
When run the output will be:
Negative of 10 is -10
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:
%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);
Java use of the sub function:
int[] r = {0};
example.sub(37,42,r);
System.out.println("     37 - 42 = " + r[0]);
will give the expected result:
        37 - 42 = -5
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.

14.3.7 Structures

The low-level SWIG interface only provides a simple interface to C structures. For example :

struct Vector {
	double x,y,z;
};

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':
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);
}
These functions are then used in the resulting Java interface. For example:

// 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));
When executed will display:
x=7.8
Similar access is provided for unions and the data members of C++ classes.

14.3.8 C++ Classes

C++ classes are handled by building a set of low level accessor functions. Consider the following class :

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'):

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);
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:
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);
}
From Java, these functions can be used to access the C++ class:

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);
When executed might display:
Lager
Stout
Ale
3
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.

14.4 Java proxy classes

The low-level interface generated by SWIG provides access to C structures and C++ classes, but it doesn't look much like a class that might be created in Java. However, it is possible to indirectly use the low-level C interface to write a Java class that looks like the original C++ class. In this case, the Java class is said to "shadow" the C++ class and so are also referred to as shadow classes. That is, it behaves like the original class, but is really just a wrapper around a C++ class. This Java wrapper class falls under the design pattern known as a proxy class.

14.4.1 A simple example

For our earlier List class, a Java proxy/shadow class could be written by hand like this :

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());
  }

}
Which happens to be what what SWIG usually outputs. When used in Java, we can use the class as follows:

List l = new List();
l.insert("Ale");
l.insert("Stout");
l.insert("Lager");
List.print(l);
int len = l.getLength();
System.out.println(len);
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.

14.4.2 Why write proxy classes in Java?

While one could wrap C/C++ objects directly into Java as new Java types, this approach has a number of problems. First, as the C/C++ code gets complicated, the resulting wrapper code starts to become extremely ugly.

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.

14.4.3 Automated proxy class generation

SWIG automatically generates proxy classes when you use the -proxy option:

swig -java -proxy interface.i
This will create the following files:

interface_wrap.c
interface.java

plus other .java files corresponding to each proxy class

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.

14.4.4 Compiling modules with proxy classes

No changes need to be made to the compilation process when using proxy classes.

14.4.5 Where to go for more information

Proxy classes turn out to be so useful that they are used almost all of the time with SWIG. All of the examples presented here will assume that proxy classes have been enabled. The precise implementation of proxy classes is described at the end of this chapter.

14.5 Examples

The directory Examples/java has a number of examples. Looking at these is a good way to learn how the SWIG Java extension works. The Examples/index.html in the parent direcory contains the SWIG Examples Documentation and is a useful starting point. The following sections also describe plenty of examples.

14.6 Exception handling

The SWIG %exception directive can be used to create a user-definable exception handler which can be used to convert errors in your C/C++ program into Java exceptions. The chapter on exception handling contains more details, but suppose you have a C++ class like the following:

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 :

%exception {
  try {
    $action
  }
  catch (RangeError) {
    jclass clazz = jenv->FindClass("java/lang/Exception");
    jenv->ThrowNew(clazz, "Range error");
    return $null;
  }
}
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.

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:

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));
Something similar to the following will be output when it is run:
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)

14.7 Remapping C datatypes with typemaps

This section describes how SWIG's treatment of various C/C++ datatypes can be remapped using the SWIG %typemap directive. While not required, this section assumes some familiarity with the JNI. The reader is advised to be familiar with the chapter on SWIG typemaps. Also it is best to consult JNI documentation either online at Sun's Java web site or a good book on the JNI. The following two books are recommended:

14.7.1 Default type mapping

The following table lists the default type mapping from Java to C/C++.

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

Arrays are implemented using the same mappings, for example a C array, unsigned short[SIZE], is mapped to a Java array, int[SIZE]. Note that SWIG treats the C char type as a character and char* as a string. The signed char type can be used if you want to treat char as a signed number rather than a character.

When SWIG is being used without proxy classes, longs are used for all pointers. All complex types (C/C++ structs and classes) are accessible using a Java long which holds a pointer to the underlying C/C++ object. Arrays of complex types are mapped as arrays of pointers to the type, that is a Java long[].

The output is different when SWIG is being used to generate proxy classes. Primitive types and pointers to these types remain the same; so a Java long is used for pointers to primitive types. However, for complex types, the proxy classes use a Java class which wraps the struct/class instead of a Java long. This applies to both argument parameters and return types that are complex types or pointers to complex types. Arrays of complex types turn into arrays of Java classes rather than arrays of longs.

For example, given the following C++ function call:

void AClass::func(int a, int* b, SomeClass c, SomeClass* d, SomeClass& e, SomeClass f[10]);
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:
public final static native void AClass_func(long ptr, int a, long b, long c, long d, long e, long[] f);
The Java proxy class, AClass, will contain the following function:
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.

14.7.2 What is a typemap?

A typemap is mechanism by which SWIG's processing of a particular C datatype can be overridden. A simple typemap might look like this :

%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:

System.out.println(example.fact(6));
and the output will be:
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.

14.7.3 Java typemaps

The typemaps available to the Java module include the common typemaps listed in the main typemaps section as well as the following Java specific typemaps:
 
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.

14.7.4 Typemap variables

The standard SWIG special variables are available for use within typemaps as described in the Typemaps documentation, for example $1, $input,$result etc.

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:

%typemap(check) int * %{ 
  if (error) {
    SWIG_exception(SWIG_IndexError, "Array element error");
    return $null;
  }
%}
If the typemap gets put into a function with void as return, $null will expand to nothing:
void jni_fn(...) {
    if (error) {
      SWIG_exception(SWIG_IndexError, "Array element error");
      return ;
    }
  ...
}
otherwise $null expands to NULL
jobject jni_fn(...) {
    if (error) {
      SWIG_exception(SWIG_IndexError, "Array element error");
      return NULL;
    }
  ...
}

14.7.5 Typemaps for C and C++

JNI calls must be written differently depending on whether the code is being compiled as C or C++. For example C compilation requires the pointer to a function pointer struct member syntax like
const jclass clazz = (*jenv)->FindClass(jenv, "java/lang/String");
whereas C++ code compilation of the same function call is a member function call using a class pointer like
const jclass clazz = jenv->FindClass("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 this
const jclass clazz = JCALL1(FindClass, jenv, "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.

14.7.6 Name based type conversion

Typemaps are based both on the datatype and an optional name attached to a datatype. For example :

%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 { ... }

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.

Due to the name-based nature of typemaps, it is important to note that typemaps are independent of typedef declarations. For example :

%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)

To get around this problem, the %apply directive can be used as follows :

%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.

14.7.7 Converting Java String arrays to char **

A common problem in many C programs is the processing of command line arguments, which are usually passed in an array of NULL terminated strings. The following SWIG interface file allows a Java String array to be used as a char ** object.

%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];
}

%}
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:

// 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]);
  }
}
When compiled and run we get:
$ java main
argv[0] = Cat
argv[1] = Dog
argv[2] = Cow
argv[3] = Goat
0:Dave
1:Mike
2:Susan
3:John
4:Michelle
Our type-mapping makes the Java interface to these functions more natural and easy to use.

14.7.8 Using typemaps to return arguments

A common problem in some C programs is that values may be returned in arguments rather than in the return value of a function. The typemaps.i file defines INPUT, OUTPUT and INOUT typemaps which can be used to solve some instances of this problem. This library file uses an array as a means of moving data to and from Java when wrapping a C function that takes pointers as parameters.

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.

/* Returns a status value and two values in out1 and out2 */
int spam(double a, double b, double *out1, double *out2);
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:
%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);
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.

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:

// 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());
  }
}
When compiled and run we get:
$ java main
1 12.0  340.0

14.7.9 Accessing array structure members

Consider the following data structure :

#define LEN   5
typedef struct {
  int numbers[LEN];
} Data;
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:

%typemap(memberin) int[LEN] {
  /* Copy at most LEN characters into $1 */
  memcpy($1,$input,sizeof(int)*LEN);
}
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.

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.

14.7.10 Pointer handling

Mapping of C pointers in the Java module is done through a simple Java long, whereas other language modules use an encoding of the pointer in a string. This means that the Java module does not use the SWIG runtime type checker the type checking functionality that the it offers is thus lost. However most of the SWIG language modules are scripting languages and they need runtime type checking whereas Java can offer static type checking. Using the Java proxy classes makes use of static type checking, however this is not the case when pointers to primitive types or unknown types. It is easy to pass any x* pointer to a function that takes, say, a y* pointer. This is likely to be addressed through static type checking in a future version of SWIG, but in the meantime, great care must be taken if using the naked pointers held in a Java long.

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.

14.8 The gory details of proxy classes

This section describes the process by which SWIG creates proxy classes and some of the more subtle aspects of using them.

14.8.1 A simple proxy class

Consider the following barebones C++ class:

%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);
  }

}

14.8.2 Generated class

Proxy classes are built using the low-level SWIG generated C interface. The simple interface is wrapped into a Java class named after the module name, 'example' here. The Java code for the proxy class is created in many different files. The name of each file is the name of the proxy class, which in turn is named after the class/struct/union that is being proxied (shadowed). This has to be the case as in Java a class called 'A' must be in a file called A.java. Except for a couple of memory management methods and constructors, the methods in the proxy class simply call the SWIG generated functions in the simple interface. The proxy class is a lot easier to use as it wraps the C++ 'this' pointer making memory management a lot easier and less error prone. Proxy classes generally fit in with the Java programming paradigm.

14.8.3 The this pointer

Each generated proxy class has the above member variables and functions, except derived classes, which will be covered later. The swigCPtr holds the pointer to an instance of the C/C++ class/struct/union, so it contains the C++ 'this' pointer. The C pointer held in swigCPtr is private data. If you need the pointer it can be obtained by using getCPtrNAME(), where NAME is the name of the proxy class. The proxy classes have been written with easy memory management in mind for most cases so you should generally not need to use swigCPtr, nor its public accessor function.

14.8.4 Object ownership

Ownership is a critical issue when mixing C++ and Java. For example, suppose I create a new object in C++, but later use it to create a Java object. If that object is being used elsewhere in the C++ code, we clearly don't want Java to delete the C++ object when the Java object is deleted. Similarly, what if I create a new object in Java, but C++ saves a pointer to it and starts using it repeatedly. Clearly, we need some notion of who owns what. Since sorting out all of the possibilities is probably impossible, the proxy class always has an attribute "swigCMemOwn" that indicates whether or not Java owns an object.

The default object ownership falls into 2 cases:

  1. Whenever an object is created in Java, Java will be given ownership by setting swigCMemOwn to true.
  2. When a Java class is created from a pre-existing SWIG generated proxy class, ownership is assumed to belong to the C/C++ code and swigCMemOwn will be set to false.
When swigCMemOwn is set, Java will attempt to call the C/C++ destructor when the object is deleted, that is garbage collected. If it is zero, Java will never call the C/C++ destructor. Ownership of an object is set up using the appropriate constructors. Note that sometimes the garbage collector does not call finalizers. Please see the Proxy classes and garbage collection section for more information.

14.8.5 Constructors and destructors

C++ constructors are mapped into an equivalent Java constructor. An additional 'proxy' constructor is available for use which overrides the default memory handling/memory ownership. For the above example, this constructor is shown as:
  public Simple(long cPtr, boolean cMemoryOwn){
    swigCMemOwn = cMemoryOwn;
    swigCPtr = cPtr;
  }
It allows one to override the above default swigCPtr and swigCMemOwn values on construction.

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:

  protected Simple() {
    swigCPtr = 0;
    _cMemOwn = false;
  }
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.

14.8.6 Member data

Member data of a C/C++ object is accessed through getter and setter methods. For example, if a public member variable and a public static member variable is added to the previous bare bones class as such:

class Simple {
public:
    Simple() {};
    ~Simple() {};
    int Number;
    static int StaticNumber;
};
The class can be used as follows to read and write to the variables:
Simple simp = new Simple();
simp.setNumber(10);
int number = simp.getNumber();

Simple.setStaticNumber(10);
number = Simple.getStaticNumber();
Note that the C++ static member variable is mapped using Java static getters and setters.

14.8.7 Proxy functions

Suppose you have the following declarations in an interface file :

%module example
struct Vector {
    Vector();
    ~Vector();
    double x,y,z;
    static Vector addv(Vector a, Vector b);
};
By default in the simple SWIG interface, the function addv will operate on Vector pointers (a Java long), not Java classes:
// Member function in class example (SWIG's simple interface)
  public final static native long Vector_addv(long jarg0, long jarg1);
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 Vector (the proxy class)
public static Vector addv(Vector a, Vector b) {
  return new Vector(example.Vector_addv(a.getCPtrVector(), b.getCPtrVector()), true);
}
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:

Vector v = Vector.addv(Vector.addv(Vector.addv(Vector.addv(a,b),c),d),e);

14.8.8 Proxy class pointer handling

Now let's take the previous example and in a new function cross_product and use Vector pointers for the parameters as well as the return type:
%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);
};
By default in the simple SWIG interface, the function cross_product will also operate on Vector pointers (a Java long):
// Member function in class example (SWIG's simple interface)
  public final static native long Vector_cross_product(long jarg0, long jarg1);
When using proxy classes, the Java SWIG module still allows us to use a Vector proper:
// 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);
  }

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.

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:

Vector nullVector = new Vector(0, false);
This can be passed in to any function taking a Vector*.

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.

14.8.9 Methods that return new objects

By default SWIG assumes that constructors are the only functions returning new objects to Java. However, you may have other functions that return new objects as well. If we take our previous Vector example and examine the cross_product implementation:

Vector *Vector::cross_product(Vector *v1, Vector *v2) {
    Vector *result = new Vector();
    result = ... compute cross product ...
    return result;
}
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 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());
Unfortunately, this is ugly, is likely to be forgotten and it doesn't work if we use the result as a temporary value :

Vector w = Vector.addv(Vector.cross_product(a,b),c);     // Results in a memory leak
However, you can provide a hint to SWIG when working with such a function as shown :

// C/C++ Function returning a new object
struct Vector {
...
%new static Vector *cross_product(Vector *v1, Vector *v2);
...
};
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:

// 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);
  }

14.8.10 Global variables and functions

Substitution of complex datatypes occurs for all proxy functions and proxy member functions involving structures, unions or class definitions. Currently no proxy classes are produced for global variables nor global functions. Only the low-level C interface is produced. This is an important limitation. The recommended approach is to put all global access into a dummy structure with static function access:

%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); }
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:
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); 
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.

14.8.11 Nested objects

SWIG proxy classes support nesting of complex objects. For example, suppose you had the following interface file :

%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 :

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) );
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.

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;

Access is provided like this:

ValueStruct v = new ValueStruct();
// ... populate ValueStruct somehow ...

long dataType = v.getDataType();
int intval = v.getU().getIntval();
double f = v.getU().getV().getF();
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:

//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.

14.8.12 Inheritance and proxy classes

SWIG will also shadow inheritance chains. For example, given the base class Shape and its derived class Circle:
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 base class Shape is generated much like any other proxy class seen so far:
// 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);
  }

}
The Circle class extends Shape mirroring the C++ class inheritance hierarchy.
// 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);
  }

}
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.

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.

14.8.13 Proxy classes and garbage collection

If you get SWIG to produce proxy classes, you will notice the generated _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:

  1. Call the 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.
  2. From jdk1.3 onwards a new function, 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:
      static {
        Runtime.getRuntime().addShutdownHook( 
          new Thread() {
            public void run() { System.gc(); System.runFinalization(); }
          }
        );
      }
    
    Although this usually works, the documentation doesn't guarantee that 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.
  3. Call the _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:
    A 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
    
    The SWIG generated code ensures that the memory is not deleted twice, in the event the finalizers get called in addition to the manual _delete() call.
  4. Write your own object manager in Java. You could derive all SWIG classes from a single base class which could track which objects have had their finalizers run, then call the rest of them on program termination. Currently you cannot tell SWIG to derive a SWIG proxy class from any named Java class, but this is planned in the near future. An alternative is to add the object handling code to all generated proxy classes using the shadow pragma.

14.8.14 Performance concerns and hints

Proxy classing is primarily intended to be a convenient way of accessing C/C++ objects from Java. However, if you're directly manipulating huge arrays of complex objects from Java, performance may suffer greatly. In these cases, you should consider implementing the functions in C or thinking of ways to optimize the problem. Try and minimise the expensive JNI calls to C/C++ functions, perhaps by using temporary Java variables instead of accessing the information directly from the C/C++ object.

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).


14.9 Java pragmas

There are two groups of pragmas in the Java module. The first group modify the Java module output file and the second modify the Java proxy output file. The pragmas beginning with module apply to the module output file. The pragmas beginning with allshadow apply to all shadow output classes. The pragmas beginning with shadow apply to the currently active shadow class so these pragmas can only be specified within the definition of a class or struct. Some examples:
/* 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;

Note that pragmas will take either " " or %{ %} as delimeters. If the pragma requires the string quote it must be preceded with a backslash or alternatively use the %{ %} delimeters, for example either of these can be used to obtain the desired effect:
%pragma(java) modulecode= "  public void sayHello() { System.out.println(\"Hello\"); } "
%pragma(java) modulecode=%{  public void sayHello() { System.out.println("Hello"); } %}

A complete list of pragmas follows:

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"

14.9.1 Deprecated pragmas

The following pragmas were in Swig 1.3a3 and have since been deprecated:
import: Please replace with moduleimport, shadowimport and/or allshadowimport pragmas.
module: Please replace with the modulecode pragma.
shadow: Please replace with the allshadowcode pragma.
modifiers: Please replace with the modulemethodmodifiers pragma.

14.9.2 Pragma uses

The pragmas are used primarily to modify the default Java output code. They provide flexibility as to how Java and C++ interact. In the pragma notation below, xxxcode for example would be used to denote the 3 similar 'code' pragmas, that is modulecode, shadowcode and allshadowcode.

14.9.2.1 Derive C++ from Java and visa-versa

It is possible to derive a Java class from a shadow class (i.e. a C++ class) with the Java module. However, with the pragmas it is also possible to derive the SWIG produced Java shadow classes (i.e. C++ class) from your own Java class by using the xxxbase pragma with the xxximport, xxxcode and xxxclassmodifiers pragmas. It is also possible for the SWIG produced Java classes to implement interfaces using the xxxinterface pragmas.

14.9.2.2 JavaDoc and the shadowcode pragma

The SWIG documentation feature is not currently present in the 1.3 versions of SWIG. However a limited form of JavaDoc documentation can be implemented by placing JavaDoc comments in the shadowcode pragma. Just put your JavaDoc comment in a shadowcode pragma before the function to which you want it to apply.

14.9.2.3 Tips for using the shadow pragmas

Note that an out of scope warning is issued if any of the shadow pragmas are used outside of the class/struct/union definition. This requires one of these pragmas to be placed within the definition of the class/struct/union. It may seem that the original C/C++ code has to be modified when using the %include pragma. A technique to avoid this is to place the pragma within the %extend directive. For example:
%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 */"
}

14.10 Dynamic linking problems

The code to load a native library is System.loadLibrary("name"). This can fail and it can be due to a number of reasons.

The most common is an incorrect naming of the native library for the name passed to the 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.

14.11 Using your own JNI methods

Perhaps you have some hand written JNI functions that you want to use in addition to the SWIG generated JNI functions? This can be accomplished using the %native directive or the %ignore directive depending on what you want.

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:

%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 */
}
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:
  public final static native int HandRolledJavaName(int jarg1, String jarg2, SomeJavaClass jarg3);
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.

14.12 Known bugs