java – JNI GetFieldID returning null for inner class-ThrowExceptions

Exception or error:

I have public inner class which i want to access in JNI. GetFieldID is returning null while accessing fieldId for inner class

Below is code

public class classA{
    public class classB{
    public int b1;
    }
   public int a1;
   public classB B;
}

Note : When i ran javap -s on class file i got following output

public class level1.level2.level3.classA{
public int a1;
    descriptor : I
public level1.level2.level3.classA$classB B;
    descriptor : Llevel1/level2/level3/classA$classB;

Here is class to call native function.

public class extraclass{
    private native int myfunction1(classA A);
    public int extrafunction(classA A){
        myfunction1(A);
    }
}

Native code

JNIEXPORT jint JNICALL myfunction1( JNIEnv *env, jobject obj ,jobject A)
{
    jclass cls = (*env)->GetObjectClass( env, A);
    jfieldID ja1,jB;
    int a1;

    ja1 = (*env)->GetFieldID( env, cls, "a1","I" );
    a1  = (*env)->GetIntField(env, config, ja1); // This works good.

    jB = (*env)->GetFieldID( env, cls, "B","Llevel1/level2/level3/classA$classB;" ); 
    // <<< Its crashing here with "JNI DETECTED ERROR IN APPLICATION: JNI GetFieldID called with pending exception 'java.lang.NoSuchFieldError'"

}

I tried following option too but failed

jB = (*env)->GetFieldID( env, cls, "B","LclassA$classB;" );  

Can some one suggest how to get field id of classB and access b1.

How to solve:

This one is quite old, but maybe somebody will find it useful.

It looks like in your case you have sort of a “mess” inside names of packages, fields.

It works perfectly fine with the code below:

.
|-- Makefile
|-- README.md
|-- c
|   `-- level1_level2_level3_extraclass.c
|-- java
|   `-- level1
|       `-- level2
|           `-- level3
|               |-- classA.java
|               `-- extraclass.java
|-- lib
`-- target

where classA.java contains

package level1.level2.level3;

public class classA {

  public class classB {
    public int b1 = 42;
  }

  public int a1 = 44;
  public classB B = new classB();

}

and extraclass.java is of a form:

package level1.level2.level3;

import level1.level2.level3.classA;

public class extraclass {

    static {

      System.loadLibrary("Extra");
    }

    private native int myfunction1(classA A);

    public int extrafunction(classA A){
        return myfunction1(A);
    }

    public static void main(String [] arg) {

      extraclass ex = new extraclass();
      classA a = new classA();

      System.out.println("Result: " + ex.extrafunction(a));
    }
}

When it comes to C code – it is little bit different to what you provided.

#include <jni.h>

JNIEXPORT jint JNICALL Java_level1_level2_level3_extraclass_myfunction1( JNIEnv *env, jobject obj, jobject objA)
{
    jclass cls = (*env) -> GetObjectClass( env, objA );

    jfieldID fid_a1   = (*env) -> GetFieldID( env, cls, "a1", "I" );
    int valA          = (*env) -> GetIntField( env, objA, fid_a1);

    jfieldID fid_B     = (*env) -> GetFieldID( env, cls, "B", "Llevel1/level2/level3/classA$classB;");
    jobject B_Val      = (*env) -> GetObjectField( env, objA, fid_B );

    jclass clsClassB   = (*env) -> GetObjectClass( env, B_Val );

    jfieldID fid_b1    = (*env) -> GetFieldID( env, clsClassB, "b1", "I" );
    int valB           = (*env) -> GetIntField( env, B_Val, fid_b1 );

    return valB + valA;

}

anyway, with slightly cleaned up code, and by making sure all the package names are in place, everything works as expected.

You can find distilled version here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo063

Leave a Reply

Your email address will not be published. Required fields are marked *