Android JNI get Two Fields from Java class

android, android-ndk, c++, java

Solution

I believe you should be using this to get your fields:

env->GetFieldID( clazz, "mType", "Lcom/grepwise/pongdroid/ShaderType;" );
env->GetFieldID( clazz, "mShaderSrc", "Ljava/lang/String;" )

And move the class & field getting out of the loop.

EDIT: Also this:

const jchar jShaderChr = env->GetCharField(...)

to get String value from mShaderSrc is wrong.

You should be using:

jstring jShaderStr = (jstring)env->GetObjectField(...);
const char* shaderSrc = env->GetStringUTFChars(jShaderStr, 0);
// ... here use shaderSrc
env->ReleaseStringUTFChars(hShaderStr, shaderSrc);

Problem

Before I post any code or anything, let me explain what I'm trying to accomplish: what I'm trying to do is get load shaders from an assets folder, and pass an array of `PongDroidShader` objects to C++ so it can compile and load them. In my Java class, I have a function which goes through each shader file in the shaders folder and parses it loads it into a `String` object, while also checking for what kind of shader type it is via its file extension (.e.g, a vertex would have a `.vert` extension). Once I've accomplished that, I then send it to my native `compileShaders` function, which takes the array of `PongDroidShader` objects, and the size of the array. After that, I parse and link the shaders from the JNI code. So far, I'm having trouble getting the JNI to recognize the Java code and load it into variables. What I have so far is as follows: Java Code ``` public final class PongDroidShader { public String mShaderSrc; public ShaderType mType; } private class ShaderHandler { ... private native void compileShaders(PongDroidShader[] shaders, int shaderCount); ... ``` JNI/C++ Code ``` JNIEXPORT void JNICALL Java_com_grepwise_pongdroid_PongDroid_00024ShaderHandler_compileShaders (JNIEnv * env, jobject obj, jobjectArray shaders, jint sizeOfShaders) { for( int i = 0; i < sizeOfShaders; ++i ) { jclass clazz = env->FindClass( "com/grepwise/pongdroid/PongDroidShader" ); jclass shaderTypeEnum = env->FindClass( "com/grepwise/pongdroid/ShaderType" ); jfieldID field = env->GetFieldID( clazz, "mType", "ShaderType" ); jobject shader = env->GetObjectArrayElement( shaders, i ); const jchar jShaderChr = env->GetCharField( shader, env->GetFieldID( clazz, "mShaderSrc", "java/lang/String" ) ); jstring jShaderStr = env->NewString( &jShaderChr, sizeof( jShaderChr ) ); const char* shaderStr = env->GetStringUTFChars( jShaderStr, 0 ); //TODO implement GL Shader Manipulation and Allocation here optim::Config::Log::info( "Testing shader: %s", shaderStr ); delete shaderStr; } } ``` I've omitted a lot of what exists in the code base just for the sake of simplicity. Note that even though `compileShaders` isn't shown being called, it is called by the activity class which wraps its parent class as an inner private class. So far, my log output is as follows: ``` 04-25 22:20:56.267 11985 11985 D dalvikvm: Trying to load lib /data/data/com.grepwise.pongdroid/lib/libnativepd.so 0x4051c800 04-25 22:20:56.275 11985 11985 D dalvikvm: Added shared lib /data/data/com.grepwise.pongdroid/lib/libnativepd.so 0x4051c800 04-25 22:20:56.322 11985 11985 D dalvikvm: GetFieldID: unable to find field Lcom/grepwise/pongdroid/PongDroidShader;.mType:ShaderType 04-25 22:20:56.322 11985 11985 D dalvikvm: GetFieldID: unable to find field Lcom/grepwise/pongdroid/PongDroidShader;.mShaderSrc:java/lang/String 04-25 22:20:56.330 11985 11985 I dalvikvm: at com.grepwise.pongdroid.PongDroid$ShaderHandler.compileShaders(Native Method) 04-25 22:20:56.330 11985 11985 I dalvikvm: at com.grepwise.pongdroid.PongDroid$ShaderHandler.access$1(PongDroid.java:128) 04-25 22:20:56.330 11985 11985 I dalvikvm: at com.grepwise.pongdroid.PongDroid.onCreate(PongDroid.java:72) ```

Original source