4

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?

1
  • I've put my answer in, such as it is. Sorry I couldn't be of more help. Commented Oct 13, 2009 at 21:43

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Great. I look forward to hearing more.
0

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

  }
}

Comments

-1

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

3 Comments

Yes, but if you use SWIG to bind to a C function returning Foo*, SWIG will think the function is returning a single Foo and generate a wrapper function that returns a Foo, not a Foo[].
I think that David has put his finger on the dilemma.
Please see this: stackoverflow.com/questions/1522660/java-and-sdlgetkeystate for a situation in sdljava where this occurs. SWIGTYPE_p_unsigned_char is returned. It's an object reference, which my Java compiler doesn't seem to want to turn into an array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.