Reputation: 4696
The SWIG documentation explains how a variety of input types in C, like this:
void spam1(Foo *x); // Pass by pointer
void spam2(Foo &x); // Pass by reference
void spam3(Foo x); // Pass by value
void spam4(Foo x[]); // Array of objects
... would all take a single type of argument in Java, like this:
Foo f = new Foo(); // Create a Foo
example.spam1(f); // Ok. Pointer
example.spam2(f); // Ok. Reference
example.spam3(f); // Ok. Value.
example.spam4(f); // Ok. Array (1 element)
Similarly, for return types in C:
Foo *spam5();
Foo &spam6();
Foo spam7();
... all three functions will return a pointer to some Foo object that will be assigned to a Java object variable, the final one requiring an allocation of a value type that the Java garbage collection will take care of upon release.
But suppose spam5() returns a pointer to an array. In Java, I have to use array semantics to access the individual elements, but I don't think that I can just do this:
Foo foo[] = spam5();
I don't even think the compiler would accept a cast to (Foo[]), so how does this work in SWIG?
Upvotes: 4
Views: 3830
Reputation:
you can always use directly JNI :
imagine you want to retrieve an xyz vector array
public class demo{
public native vecteur[] returnArray();
....
}
in the swig wrap cxx file add the func that will fill the java vect array
JNIEXPORT jobjectArray JNICALL
Java_demo_returnArray
(JNIEnv *env, jobject jobj){
jobjectArray ret;
int i;
jclass objClass;
jmethodID mid;
jobject myobj;
jmethodID setX;
objClass = env->FindClass("vect");
if (!objClass)
{
printf("class not found\n");
exit(0);
}
ret= (jobjectArray)env->NewObjectArray(5, // change with the size of your array or a variable
objClass,
env->NewStringUTF(""));//FIXME
// call javap -s myclass to know the names
mid=env->GetMethodID( objClass, "<init>", "()V"); // looking for the vect class constructor
if (!mid)
{
printf("vect() not found\n");
exit(0);
}
for(i=0;i<5;i++) {
myobj=env->NewObject( objClass, mid); // myobj = new vect()
// get vect::setX method
setX=env->GetMethodID( objClass, "setX", "(F)V"); // looking for vect::setX method
if(!setX)
{
printf("method vect::setX not found\n");
exit(0);
}
// call setX method with param i
env->CallVoidMethod(myobj, setX,(float)i); // change i with your array value
env->SetObjectArrayElement(
ret,i,myobj);
}
return(ret);
}
and finally main class
// main.java
public class main {
static {
System.loadLibrary("myclass");
}
public static void main(String argv[]) {
demo l = new demo();
vecteur f[] = l.returnArray();
System.out.println("array size : "+f.length);
for (int i = 0;i < f.length;i++)
System.out.println(f[i].getX());
}
}
Upvotes: 0
Reputation: 9705
This problem does not have a simple or automatic solution. Believe me, I looked.
The problem is that SWIG doesn't know how big the array you're returning is supposed to be, so it can't generate a Java array. You can't supply the size as an argument to the function, either (gross as that would be) - typemaps don't work that way.
In the general case you have to write another wrapper function, which takes a C array and a length as an out parameter, and use a typemap to turn those two parameters into a Java array. Or, if you don't mind using carrays.i, you can skip the second step and just work with C arrays directly from Java.
Upvotes: 5
Reputation: 16528
In java an array is an Object, So, if spam5()
return Object
, then the compiler will allow you to cast that to an array of Foo. This is valid Java:
class Bar {
static class Foo {}
Foo[] foo = {new Foo(), new Foo()};
Object o = foo;
// ...
Foo[] bar = (Foo[])o;
}
Upvotes: -1