I created JNI wrapper for the following c++ code.
add.h
class MyClass
{
public:
int add(int x, int y, int &z);
int sub(int x, int y);
};
The above mentioned code is the .h file
add.cpp
int MyClass::add(int x, int y, int &sum)
{
sum=x+y;
return 0;
}
int MyClass::sub(int x, int y)
{
return x - y;
}
swig.i
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include "arrays_java.i"
%include "typemaps.i"
%include "add.h"
For the above mentioned .cpp file , I need to generate JNI wrapper and use it on the Java code. When I am trying to execute the swig command , I get the SWIGTYPE_p_int.java file along withe JNI file. Can anyone help me to overcome this problem?
To wrap C++ "return by non-const reference" functions there are quite a few options open. In brief you can do one of:
%extend
to provide an overload that returns instead. (Optionally hide the original)SWIGTYPE_p_int
more. (Optionally build an overload inside of Java)OUTPUT
typemaps to get pass by reference semantics with an arrayI'll show an example of each option here.
%extend
to provide an overloadThe basic idea here is that we're going to write an entirely new overload here that SWIG wraps trivially. Using the %extend
syntax below we can create a new, wrapper only, overload that uses a temporary to store the value and then returns it if all goes well.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
#include <exception>
%}
%extend MyClass {
int add(int x, int y) {
int z;
const int result = $self->add(x,y,z);
if (0 == result) return z;
throw std::exception();
// TODO: use SWIG's exception support
}
}
%ignore MyClass::add(int,int,int&); // Optional: hide the original overload
%include "add.h"
Since the original returned int seems to indicate success/failure of the function itself we can map that more naturally onto exceptions in Java. (Details omitted here, see my answer at XXX for more)
The effect of this solution is similar to the previous one, but implemented in a different way. Here we're using the in
typemap with numinputs=0
to set up a temporary variable that we can use (tmpz
) when the call happens. The out typemap then just checks the return code from the real functioncall, with the argout typemap copying the tempoary into the result. I included more typemaps than really needed here, because by chance z
and the existing function return are the same type but we'd need them if that weren't the case.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
#include <exception>
%}
// These aren't actually needed here because the fuction already returns in
%typemap(jni) int MyClass::add "jint";
%typemap(jtype) int MyClass::add "int";
%typemap(jstype) int MyClass::add "int";
%typemap(javaout) int MyClass::add {
return $jnicall;
}
// These create a temporary and map it to the return value for us
%typemap(argout) int& z {
$result = (jint)tmpz$argnum;
}
%typemap(out) int MyClass::add {
if ($1 != 0) {
throw std::exception();
// TODO: exceptions as in other examples
}
}
%typemap(in,numinputs=0) int& z (int tmpz) {
$1 = &tmpz;
}
%include "add.h"
Here we're going to use SWIG's cpointer.i
library to help us work with SWIGTYPE_p_int
objects and do that transparently for our Java users. To do so we've used the javacode typemap to create a temporary variable for z
and then passed that into the original SWIG generated function (which can be made private to hide it). As with the other examples we can handle the case where the return value indicates an error by throwing an exception, this time though it's already Java code that's doing the throwing which is slightly simpler.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include "cpointer.i"
%pointer_class(int,IntPointer);
%typemap(javacode) MyClass %{
public int add(int x, int y) {
IntPointer z = new IntPointer();
int ret = this.add(x,y,z.cast());
if (ret != 0) throw new Exception();
return z.value();
}
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private" // Optional
%include "add.h"
OUTPUT
typemapsThis is functionally very similar to the previous solution, with the change that instead of using a SWIG supplied helper type for handling the int pointer we use an array and exploit Java's "arrays pass by reference" semantics under the hood to achieve the same result.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%include <typemaps.i>
%apply int *OUTPUT { int & z };
%typemap(javacode) MyClass %{
public int add(int x, int y) {
int[] z = new int[1];
int ret = this.add(x,y,z);
if (ret != 0) throw new Exception();
return z[0];
}
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private"
%include "add.h"
You can add another type using %inline
. And then trick SWIG into using that instead of the int&
reference. Provided we allow an implicit conversion this is fine.
%module algo
%{
#define SWIG_FILE_WITH_INIT
#include "add.h"
%}
%inline %{
struct IntWrapper {
int value;
// Enable transparent conversion for the SWIG argument
operator int&() {
return value;
}
};
%}
class MyClass
{
public:
int add(int x, int y, IntWrapper& z); // lie to SWIG, but we'll make it up later with implict conversion
int sub(int x, int y);
};
//%include "add.h" // Don't do this now because we need the lie above
As with the previous examples we could choose to hide this implementation detail from Java users with an overload and method modifier usage.
For more on the exceptions points raised in several examples above see here, or here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With