6

How do I set Java enum field from JNI ? Here is the sample code. I would like to set "myState" field of my B object in the native function "get_state".

public class A {

    public enum STATE { 
        STATE_ONE,
        STATE_TWO
    }

    public static class B {
        public STATE myState;
    }

    public native void get_state(B b);

    public B getB() {
        B b;

        // Call JNI to get the state
        get_state(b);

        return b;
    }
}


JNIEXPORT void JNICALL Java_A_get_1state(JNIEnv *env, jobject object, jobject b_object)
{
    /* Get a reference to obj's class */
    jclass cls = (*env)->GetObjectClass(env, b_object);

    //How do I set B object's "myState" field?

}
user2956951
  • 61
  • 1
  • 2
  • Possible duplicate of [how to return enum from JNI](https://stackoverflow.com/questions/11225261/how-to-return-enum-from-jni) – Artem Mostyaev Dec 21 '17 at 09:59

3 Answers3

6

Since it is a nested enum class, STATE is implicitly static. There are numerous resources, but a Google search that says exactly this can be found here: http://www.javapractices.com/topic/TopicAction.do?Id=1

This allows for another approach on top of valueOF methodID from enum class. You can use env->GetStaticField and env->GetStaticObjectField to get the enum to set.

Ex:

jclass theStateClass = env->FindClass("your/containingPackage/A$STATE");
jfieldID stateOneField    = env->GetStaticFieldID(theStateClass, "STATE_ONE", "Lyour/containingPackage/A$STATE;");
jobject STATE_ONE = env->GetStaticObjectField(theStateClass, stateOneField);
user3259330
  • 448
  • 6
  • 9
blkhatpersian
  • 437
  • 6
  • 18
  • 1
    This is brilliant but the example given is incorrect. I'll attempt to edit it but essentially STATE_ONE and STATE_TWO are static final members of class STATE so GetStaticObjectField and ..FieldID need a class reference to STATE not A – user3259330 Sep 02 '16 at 18:48
  • All the responses here slightly miss the point of the original question. That is, is it possible to update an instance (non-static declared) Enum type field, a field declared in the same Java class as a native method/JNI function, directly from within the JNI function (without updating the class field using an assignment from the JNI function's return type, returning an jobject). If so, how? – BoiseBaked Apr 09 '17 at 16:12
0

Just like you would do it from Java when you only have the name of the enum:

  1. Look up the class instance via JNI.
  2. Invoke the valueOf(String) method on the enum class
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I would like to set the said enum field, similarly if the said field was of type String `char* str = strdup("Hello"); jfieldID fid = (*env)->GetFieldID(env, cls, "myState", "Ljava/lang/String;"); jstring jstr = (*env)->NewStringUTF(env, str); (*env)->SetObjectField(env, b_object, fid, jstr); free(str); (*env)->DeleteLocalRef(env, jpin);` So how can i invoke SetObjectField or similar method on java enum type field on my b_object? – user2956951 Nov 05 '13 at 17:30
  • As I said: Invoke `STATE.valueOf("STATE_ONE")` from JNI to get the instance and then use `SetObjectField` with the value to change the field. – Aaron Digulla Nov 05 '13 at 21:39
0

Inolder to build this class,I had done some minor modification.

public class A {

    public enum STATE { 
        STATE_ONE,
        STATE_TWO
    }

    

    public native void get_state(B b);

    public B getB() {
        B b = new B();

        // Call JNI to get the state
        get_state(b);

        return b;
    }
    
    public static class B {
        public STATE myState = STATE.STATE_ONE;
        
    }
}

so here we go. the first step is to build the java class

javac A.java

so We got an A.class file.

second,generate the signature.

javap -v A

the shell prints the following:

C:\Users\bowman\Desktop\project>javap -v -p -c A
Classfile /C:/Users/bowman/Desktop/project/A.class
  Last modified 2014-1-3; size 377 bytes
  MD5 checksum f331eddf740b0d8c256c851f04369088
  Compiled from "A.java"
public class A
  SourceFile: "A.java"
  InnerClasses:
       public static #7= #2 of #5; //B=class A$B of class A
       public static final #10= #9 of #5; //STATE=class A$STATE of class A
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#21         //  java/lang/Object."<init>":()V
   #2 = Class              #22            //  A$B
   #3 = Methodref          #2.#21         //  A$B."<init>":()V
   #4 = Methodref          #5.#23         //  A.get_state:(LA$B;)V
   #5 = Class              #24            //  A
   #6 = Class              #25            //  java/lang/Object
   #7 = Utf8               B
   #8 = Utf8               InnerClasses
   #9 = Class              #26            //  A$STATE
  #10 = Utf8               STATE
  #11 = Utf8               <init>
etc...

the main point is :

public class A

SourceFile: "A.java"

InnerClasses:

public static #7= #2 of #5; //B=class A$B of class A

public static final #10= #9 of #5; //STATE=class A$STATE of class A

so We can make a consulation that the enum is a class which has a signature of "A$STATE"

you can get this class in cpp by:

jclass A_State = env->FindClass( "LA$STATE;");

hope it helps.

Community
  • 1
  • 1
bowman han
  • 1,097
  • 15
  • 25