1

I'm declaring an inline native JNI function, getId. I'm unsure of how to tell SWIG, in the %native snippet below, how to just return a java.lang.Object. I have TBD there for now. I believe a typemap is the proper approach, but I'm unsure of how to declare it for a native JNI method using the %native function. Any ideas?

%module Sample
%{
JNIEXPORT jobject JNICALL Java_com_test_SampleJNI_getID(JNIEnv *env, jclass cls) 
{
    jmethodID cnstrctr;
    jvalue args[2];
    jobject obj;
    jbyteArray bArray;

    bArray = (*env)->NewByteArray(env, 32);

   (*env)->SetByteArrayRegion(env, bArray, 0, 32, (jbyte *)foo);

   cls = (*env)->FindClass(env, "com/test/jni/DeviceId");
   cnstrctr = (*env)->GetMethodID(env, cls, "<init>", "(ILjava/lang/String;[B)V");

   args[0].i = (*env)->NewStringUTF(env, "id");
   args[1].i = bArray;

   obj = (*env)->NewObjectA(env, cls, cnstrctr, args);

   return obj;
}
%}
%native(getID) TBD getID();

DeviceId.java:

package com.test.jni;

public class DeviceId {
    private String id;
    private byte[] cache;

    public DeviceId(String id, byte[] cache){
        this.id=id;
        this.cache=cache;
    }

    public byte[] getCache() {
        return cache;
    }

    public void setCache(byte[] cache) {
        this.cache = cache;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }   
}
2
  • What do you mean "find a class and populate it?". Do you want to return a new Java Object? Or a SWIG wrapped C++ object? Commented Apr 12, 2012 at 10:06
  • @awoodland - A new Java object (instace of DeviceId). I added some code to show what the intent is. The main issue is knowing how to handle the jobject return type of the getID inline function within the %native snippet. Commented Apr 12, 2012 at 16:08

1 Answer 1

1

You can use typemaps (e.g. jtype and jstype most likely) with %native, but you can also just say simply jobject if you have an Object being returned and have it handled for you, e.g.:

%module Sample
%{
JNIEXPORT jobject JNICALL Java_com_test_SampleJNI_getID(JNIEnv *env, jclass cls) 
{
  jclass c = (*jenv)->FindClass(env, "java/lang/Object");
  jmethodID m = (*jenv)->GetMethodID(env, c, "<init>", "()V");
  return (*env)->NewObject(env, c, m);
}
%}
%native(getID) jobject getID();

If you wanted to return something else (say java.lang.Integer) you would do something like:

%module Sample
%{
JNIEXPORT jobject JNICALL Java_com_test_SampleJNI_getID(JNIEnv *env, jclass cls) 
{
  jclass c = (*jenv)->FindClass(env, "java/lang/Integer");
  jmethodID m = (*jenv)->GetMethodID(env, c, "<init>", "()V");
  return (*env)->NewObject(env, c, m);
}
%}

%typemap(jstype) int getID "Integer"
%typemap(jtype) int getID "Integer"
%native(getID) int getID();

I specified getID explicitly in that typemap to avoid it being applied to all ints.

(I tested the SWIG part of this is generating sensible code, but I didn't verify the JNI and it clearly needs checking of return values)


For your specific example you could do:

%typemap(jstype) DeviceID getID "com.test.jni.DeviceId"
%typemap(jtype) DeviceID getID "com.test.jni.DeviceId"
%typemap(javaout) DeviceID getID { return $jnicall; }
%native(getID) DeviceID getID();

i.e. you can write literally anything name that isn't already being used for something else and just apply a typemap.

But it's probably best to go with jobject as the return type as then you can just write:

%typemap(jstype) jobject getID "com.test.jni.DeviceId"
%typemap(jtype) jobject getID "com.test.jni.DeviceId"
%native(getID) jobject getID();
Sign up to request clarification or add additional context in comments.

9 Comments

It wont let me edit your post but I think there is a small typo, *jenv should be *env, was getting compile issues.
are you able to compile with the JNI function in a header file and not inlining it? I'm only able to get it to work if I place the full JNI function/code in the swig.i file. I keep getting a complie error of Sample.h:797: Error: Syntax error in input(1) when I declare JNIEXPORT jobject JNICALL Java_com_test_Sample_getID(JNIEnv *env, jclass cls); in my Sample.h file.
one more question...shouldn't you be able to do jclass c = (*env)->FindClass(env, "com.test.jni.DeviceId"); if I wanted to return a particular instance of a class? The reason for this is that I want to populate the com.test.jni.DeviceId class in the JNI method and return a fully populated version. Thanks for all the help!
@c12 - You're right about the extra j creeping in - that's what SWIG calls it in typemaps normally. If it's in a different file I think you will need an extra #include. I don't follow the FindClass question. FindClass just looks up the information about the class, not about specific instances of it.
@c12 yes. There will be a module.java and moduleJNI.java generated. jtype is the JNI result (often just a long for a pointer) and jstype is for the proxy. The jstype typemap has to convert between the two as required.
|

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.