Buggieboy
Buggieboy

Reputation: 4696

SWIG pointers and Java arrays

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

Answers (3)

user195301
user195301

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

David Seiler
David Seiler

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

Devon_C_Miller
Devon_C_Miller

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

Related Questions