First, the crucial intermediary JNI class is considered. SWIG wraps C/C++ code using Java proxy classes and is very useful if you want to have access to large amounts of C/C++ code from Java. The C functional interface has been completely morphed into an object-oriented interface and change the ownership of an object. Suppose that you defined a SWIG module such as the following: To build a Java module, run SWIG using the -java option : This creates two different files; a C/C++ source file example_wrap.c or incomplete type information. This is the default approach to wrapping named enums. The application of a typemap to specific datatypes and argument names involves Solaris, you often need to add an extra library -lCrun like this: If you aren't entirely sure about the linking for C++, you For example: No C JNI function will be generated and the Java_packageName_moduleName_HandRolled function will be accessible using the SWIG generated Java native method call in the intermediary JNI class which will look like this: and as usual this function is wrapped by another which for a global C function would appear in the module class: The packageName and moduleName must of course be correct else you will get linker errors when the JVM dynamically loads the JNI function. Note that the JNI code above uses a number of string lookups to call a constructor, whereas this would not occur using byte compiled Java code.
to raise exceptions. This in turn will call its underlying C++ destructor which The latter sections cover the advanced techniques of using typemaps for complete control of the wrapping process. See the C/C++ to Java typemaps section for more details.
This section includes a few examples of typemaps. One might wonder why the common code that SWIG emits for the proxy and type wrapper classes is not pushed into a base class. SWIG takes advantage of this feature to facilitate wrapping C/C++ enums that have initializers. Many other SWIG language modules use an encoding of the pointer in a string. Thus the upgrade path to proper enums provided in JDK 1.5 is more painful. When it is resurrected JavaDoc comments will be fully supported. from modulename to modulenameModule. Like the typesafe enum pattern, the constructors are private. Foo object. In other words the typemap provides the conversion from the native method call return type. For example. This exception class is a runtime exception and therefore not a checked exception. will not have the intended effect since typemaps.i does not define an OUTPUT rule for Bar. Make sure the environment variables for MSVC++ are available and the MSVC++ tools are in your path. The 'javain' typemap matches the input parameter type for the setElement method. If all else fails, you can use the downcastXXXXX() method to attempt to recover the director class's Java object pointer. there are only instances of classes. This would be done by using the original versions of these typemaps in "enums.swg" under another typemap name for applying using %apply. The module class can be tailored through the use of pragmas, in the same manner as the intermediary JNI class. This typemap provides the conversion for the parameters in the director methods when calling up from C++ to Java. The example demonstrates how you can target particular constants (BIG and LARGE) with %javaconst. From Java, the intention is then to call into a modifed API with something like: To achieve this mapping, we need to alter the default code generation slightly so that at the Java layer, There are also many regression tests in the Examples/test-suite directory. Thus all virtual method calls, whether they originate in C++ or in Java via proxy classes, eventually end up in at the implementation in the director class. can be wrapped with the Java equivalent, that is, static inner proxy classes. JNI documentation can be consulted either online at Sun's Java web site or from a good JNI book. more aggressive from gcc-4.0 onwards and will result in code that fails with strict aliasing optimisations turned on. proxy class files nor a Java keyword. The default Proper Java enums approach to wrapping enums is somewhat verbose. On Windows make sure the path environment variable contains the path to the native library. Sometimes when you create a module, it is missing certain bits of functionality. Default contains extra constructors, memory ownership control member variables (. If we had, we would have put it in the "in" typemap which, like all JNI and Java typemaps, also supports the 'throws' attribute. You are advised to be familiar with the the material in the "Typemaps" chapter. In reality, the "appropriate place" is one of only two possibilities: C++ or Java. Note that the module name does not define a Java package and by default, the generated Java classes do not have a Java package. The following interface file code should be placed before SWIG parses the above C code. However, true cross language polymorphism can be achieved using the directors feature. The following sub-sections detail the various types of enum classes that can be generated. Thus, for director-enabled classes and only for director-enabled classes, the generated proxy Java code looks something like: When you import a SWIG interface file containing class definitions, the classes you want to be director-enabled must be have the feature("director") enabled for type symmetry to work. Let's take a look at an example. the proxy class's finalizer will destroy the C++ object when the proxy class is The "javatype" typemap has changed the parameter type to, The code in the 'pre' attribute appears before the JNI call (. Open up the C++ wrapper source code file and look for "method_foo" (include the double quotes, they are important!) The code in the second typemap constitutes the bulk of the code in the generated getWheel() function: Managing memory can be tricky when using C++ and Java proxy classes. If set to true, On Windows the native library must then be called name.dll and on most Unix systems it must be called libname.so. If your SWIG installation went well Unix users should be able to type make in each example directory, then java main to see them running. For example: C++ classes are wrapped by Java classes as well. Use _wrap.cxx instead of _wrap.c in the instructions above and add -c++ when invoking swig. represent types. On Unix make sure that your LD_LIBRARY_PATH contains the path to the native library. For example: When char * members of a structure are wrapped, the contents are assumed to be Narrowing where the Java compiler automatically and preferentially selects the 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 "argout" typemap sometimes sets values in function parameters which are passed by reference in Java. It is possible to initialize all wrapped constants from pure Java code by placing a %javaconst(1) before SWIG parses the constants. To change this, you can use the -o option. So in summary, the C/C++ pointer to non-primitive types is cast into the 64 bit Java long type and therefore the JNI type is a jlong. If an "in" typemap is written, a "freearg" and "argout" typemap may also need to be written might look at the files "java.swg" and "typemaps.i" in If the ';' is left out, Java will generate a "method not found" runtime error. Here the default typemaps work for int and char *. For more examples, you The problem here is that a type wrapper class is generated for the two dimensional array parameter so Elements of proxy classes and type wrapper classes come from the following typemaps (the defaults). First let's look at the code that is generated by default, where the Java proxy class CDate is used in the proxy interface: The CDate & and const CDate & Java code is generated from the following two default typemaps: where '$javaclassname' is translated into the proxy class name, CDate and '$javainput' is translated into the name of the parameter, eg dateIn. All native methods go through the intermediary class which has the native method declared as such: The second parameter, jarg1_, is the premature garbage collection prevention parameter and is added to the native method parameter list whenever a C/C++ struct or class is marshalled as a Java long. constructor. This example demonstrates how a C++ date class, say CDate, can be mapped onto the standard Java date class, Do not forget the terminating ';' for JNI field descriptors starting with 'L'. For example: C pointers in the Java module are stored in a Java long and cross the JNI boundary held within this 64 bit number. Once obtained, a type wrapper object can be freely passed around to different C functions that is a useful reference for compiling on different platforms. 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 that runFinalization() will actually call the finalizers. functions like this. The default code generated by SWIG for the Java module comes from the typemaps in the "java.swg" library file which implements the if you have two functions like this: You can use them in Java in a straightforward manner: Similarly, if you have a class like this. subsystem. The implementation for this extra parameter generation requires the "jtype" typemap to contain long and the "jstype" typemap to contain the name of a proxy class. Needless to say, this approach is not going to suit all applications. Author: Rob Gordon. Further details on default arguments and how to restore this approach are given in the more general Similar access is provided for unions and the public data members of C++ classes.
The typemap code simply fills in the appropriate values from If you are using the examples that ship with SWIG, then the Examples/Makefile must have these set up correctly for your system. This chapter describes SWIG's support of Java. %constant directive. Therefore, if the C memory allocator is not thread safe, then the heap will get corrupted sooner or later, when a concurrent C++ delete and new are executed. to the type used in the Java intermediary JNI class (as specified in the "jtype" typemap). The following code snippet might aid in understand aliasing rules better: An email posting, Aliasing, pointer casts and gcc 3.3 elaborates further on the subject. $result is the resulting output. If Derived is provided by the C++ code, you could for example add in a pure Java class Extended derived from Base. The $input variable contains the Java data, the JNI jint in this case. Java types.
The corrected interface file looks like: SWIG looks up the package based on the actual type (plain Foo, Foo pointer and Foo reference), so it is important to associate all three types with the desired package. The module name, specified with %module, determines the name of various generated classes as discussed later. Proper Java enums were only introduced in JDK 1.5 so this approach is only compatible with more recent versions of Java. If a C or C++ function throws an error, you may want to convert that error into a Java
ownership of the result. If a structure contains arrays, access to those arrays is managed through pointers. See Director specific typemaps for details. Now you can use a pure Java array and pass it to the C code: This approach is probably the most natural way to use arrays. When this example is compiled into a Java module, it can be used as follows: In this example, the typemap is applied to all occurrences of the int datatype. to improve the interface to existing C/C++ code. The typesafe enum pattern is a relatively well known construct to work around the lack of enums in versions of Java prior to JDK 1.5. All global functions and variable getters/setters appear in the module class. intermediary JNI class file, exampleJNI.java as well as numerous other Java proxy class files. C++ enums defined within a C++ class are generated into a static final inner Java class within the Java proxy class. The type unsafe approach is preferable to this one and this simple approach is only included for backwards compatibility with these earlier versions of SWIG. This directive is only really useful if you want to mix your own hand crafted JNI code and the SWIG generated code into one Java class or package. You can't iterate over them nor can you even query their A common problem in some C programs is handling parameters passed as simple pointers or references. Use for mapping C arrays to Java arrays (typeunsafe and simple enum wrapping approaches only). Usage from Java will simply be: Note that the Butler class is used just like any other Java class and no extra coding by the user needs to be written to
The finalize() method calls delete() which frees any malloc'd memory for wrapped C structs or calls the C++ class destructors. This code is made slightly more complicated because allowances must be made Note that SWIG wraps the C char type as a character. The generated $jnicall has been replaced by Due to the complexities of C and C++ there are different ways in which C/C++ code could be wrapped and called from Java. The following innocuous Java usage of Test is an example that will crash very quickly on a multiprocessor machine if the JNI compiled code is linked against the single thread C runtime libraries. after the function has returned. The %feature directive can be applied globally, to specific classes, and to specific methods, like this: You can use the %feature("nodirector") directive to turn off directors for specific classes or methods. symbols separate, consider wrapping them as separate SWIG modules. Second, you must use the %feature("director") directive to tell SWIG which classes and methods should get directors. type int. the throws clause contains a single instance of java.lang.Exception: If we were a martyr to the JNI cause, we could replace the succinct code within the "javain" typemap with a few pages of JNI code. Java byte array is converted to char array, Use for mapping NULL terminated arrays of C strings to Java String arrays. If you try you will get a NullPointerException. %typemap(javadestruct, methodname="delete", methodmodifiers="public synchronized"), %typemap(javadestruct_derived, methodname="delete", methodmodifiers="public synchronized"). change its value, consider writing some helper functions instead. In order to use one of these typesafe enums, the swigToEnum static method must be called to return a reference to one of the static instances. and therefore there is no possibility of premature garbage collection. Create enumerated constants in Java JavaWorld article, resulting in the following code which breaks the aliasing rules: If you are using gcc as your C compiler, you might get a "dereferencing type-punned pointer will break strict-aliasing rules" warning about this. Most debuggers do not understand both Java and C++, with one noteable exception of Sun Studio, The Java type is either the proxy class or type wrapper class. The "freearg" typemap sometimes releases memory allocated by the "in" typemap. To achieve this goal, new classes called directors are introduced at the bottom of the C++ inheritance chain. Class data members are accessed in the same manner as C structures. When a pointer is returned from a JNI function, it is wrapped using a new Java proxy class or type wrapper class. There is an alternative approach using the SWIG array library and this is covered in the next section. This is useful for typemaps that will be used in native method returning all return types. destroy, copy, assign, and dereference a pointer. To do this, you can use the %exception directive. the Java type used in the Java module class, proxy classes and type wrapper classes (as specified in the "jstype" typemap). All the methods in the intermediary JNI class will then be callable outside of the package as the method modifiers are public by default. constructor call the HireButler() method to create the underlying C object. Each enum item is also wrapped as a static final integer. It is different to using the 'javah' tool as SWIG will wrap existing C/C++ code, whereas javah takes 'native' Java function declarations and creates C/C++ function prototypes. Note that the 'C' JNI calling convention is used. One last piece of advice is to beware of the common faux pas of having more than one native library version in your path. The conversion is done in JNI code after calling the Java function from the JNI code. Usually this is not a problem as virtual functions do work by default, such as in the case of start(). In this example, 16 integers would be copied. The defaults can be overridden to tailor these classes.
The following example demonstrates the Java enums approach: SWIG will generate the following Java enum: The enum items appear first. Consider expanding our example with a new Vehicle type and a more flexible factory function: To be able to downcast with this sort of Java code: the following typemaps targeted at the vehicle_factory function will achieve this. Title: 'Essential JNI: Java Native Interface.' In Windows and Unix all memory that a process uses is returned to the system on exit, so this isn't a problem. When choosing a module name, make sure you don't use the same name as one of the generated For example, if the the module nor do namespaces result in a module that is broken up into The $javacall special variable is analogous to the $jnicall special variable. defined for an allowed constructor. the other %feature directives. See Proper Java enum classes to see the omitted support methods. Generally, this involves the use of a template class SWIG is aware of C++ namespaces, but namespace names do not appear in
The %array_class(type, name) macro creates wrappers for an unbounded array object that This applies whether the type is marshalled as a pointer, by reference or by value. This is not very difficult--you only have to make slight modifications to the the union of the exception classes is added to the throws clause ensuring there are no duplicate classes. Note that in this case, the Java class is constructed using JNI code rather than passing a pointer across the JNI boundary in a Java long for construction in Java code. ISBN: 0-13-679895-0. part of using SWIG---the default wrapping behavior is enough in most cases. SWIG handles both named and unnamed (anonymous) enumerations. In order to wrap all possible C/C++ enums using proper Java enums, the "enums.swg" file must be used. class loader that fulfills all of the above listed deficiencies though without Conversion from jstype to jtype for director methods. You could narrow the typemap matching rules by specifying a particular array size. Have a look at Sun's Java web site and search for runFinalizersOnExit. The first is not to use a Java cast but a call to C++ to make the cast. Neither C++ code nor Java code needs to know where a particular method is implemented: the combination of proxy classes, director classes, and C wrapper functions transparently takes care of all the cross-language method routing. The signed char type can be used if you want to treat char as a signed number rather than a character. check the SWIG Wiki for All destructors have to be called manually for example the delete_Foo(foo) call above. Conversion from jstype to jtype. For example, if you have this class. This section provides a brief overview The typemaps to achieve this are shown below. The intermediary JNI class can be tailored through the use of pragmas, but is not commonly done. However, again it is recommended to add in a %javaconst(1) directive. One such issue is premature garbage collection of an object created from Java and resultant usage from C++ code. Allows values held within an array to be used for C functions taking pointers for data output. That is only a getter is produced. then SWIG transforms the class into a set of low-level procedural wrappers. In fact, there is Examples include dealing with output parameters, Note that with long running programs the garbage collector will eventually run, thereby calling any unreferenced object's finalizers. Next, select the example.c and example_wrap.c files and go to the C/C++ tab and select the Precompiled Headers tab in the project settings. SWIG is run with the -c++ option). This alone can generate a lot of code bloat for large hierarchies. The default wrapping makes it hard to set or get just one element of the array and so array access from Java is somewhat limited. Lastly the "jni", "jtype" and "jstype" typemaps are also required to specify Also available. These appear in the intermediary JNI class: This class contains the complete Java - C/C++ interface so all function calls go via this class.