3

I had a requirement wherein I have an enum in native C++ code as [all pseudocode]:

enum Dummy {
 A,
 B,
 MAX,
};

Now I also want to have an equivalent enum in Java code

public static enum Dummy {
 A,
 B,
 MAX
};

Doubly defining makes things extremely brittle and error prone, subject to bouts of amnesia or indolence on part of developers. Is there some concrete way to always have them in sync. I don't want a bunch of #defines as suggested by this question.

Zoso
  • 3,273
  • 1
  • 16
  • 27

2 Answers2

3

You can create your enum with a constructor so you can assign it the value you want, then use a JNI call to get the value for that enum. Something like this in Java (note that I have not tested this code at all, but I have written similar code in the past to do exactly what you need):

public class TestEnum
{
    public enum Dummy
    {
        A( getA() );
        B( getB() );
        MAX( getMax() );

        private final int value;

        Dummy( int newValue )
        {
            this.value = newValue;
        }

        int getValue()
        {
            return( this.value );
        }

        private static native int getA();
        private static native int getB();
        private static native int getMAX();
    }

    ...
}

On the native side:

enum Dummy
{
    A = 100;
    B = 102;
    MAX = 912343;
};

...

JNIEXPORT jint JNICALL Java_TestEnum_00024TEST_getA( JNIEnv *env, jclass cls )
{
    return( A );
}
JNIEXPORT jint JNICALL Java_TestEnum_00024TEST_getB( JNIEnv *env, jclass cls )
{
    return( B );
}
JNIEXPORT jint JNICALL Java_TestEnum_00024TEST_getMAX( JNIEnv *env, jclass cls )
{
    return( MAX );
}

Make sure you use javah to generate your native function signatures and #include the generated header in your code.

Or, you can pass something else to the native function to identify the enum value to return, such as a string that maps to the actual enum value:

public class TestEnum
{
    public enum Dummy
    {
        A( get( "A" ) );
        B( get( "B" ) );
        MAX( get( "MAX" ) );

        private final int value;

        Dummy( int newValue )
        {
            this.value = newValue;
        }

        int getValue()
        {
            return( this.value );
        }

        private static native int get( String enumName );
    }

    ...
}

and on the native side:

JNIEXPORT jint JNICALL Java_TestEnum_00024TEST_get( JNIEnv *env, jclass cls, jstring enumName )
{
    char *cEnumName = (*env)->getStringUTFChars( env, enumName, NULL );
    jint retVal = -1;
    if ( 0 == strcmp( cEnumName, "A" ) )
    {
        retVal = A;
    }
    else if ( 0 == strcmp( cEnumName, "B" ) )
    {
        retVal = B;
    }
    else if ( 0 == strcmp( cEnumName, "MAX" ) )
    {
        retVal = MAX;
    }

    (*env)->ReleaseStringChars( env, cEnumName );

    return( retVal );
}

You're still going to have to deal with some O&M overhead, but this way the actual value is only defined in one place. In this case, it's in the native code.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • 1
    Thanks for your comprehensive answer but I am not sure if this proofs against accidental misses from developer. As in if he adds an enum value `x` in native code but forgets to ask the corresponding `X(getX())` in java code. Your answer does resolve the multiple definition part for sure though. Am I missing something here ? – Zoso Aug 03 '17 at 06:38
2

Go a hard, preprocessor, way ;)

/* main.cc */
#include <stdio.h>

#define public
#include "A.java"
;
#undef public

int main() {
  A val = a;
  if(val == a) {
    printf("OK\n");
  } else {
    printf("Not OK\n");
  }
}

Java code

/* A.java */
public
enum A {
  a,
  b
}

We can use A enum in Java

/* B.java */
public class B {
  public static void main(String [] arg) {
    A val = A.a;
    if(val == A.a) {
      System.out.println("OK");
    } else {
      System.out.println("Not OK");
    }
  }
}

And execute

> javac *.java
> java B
OK
> g++ -o main ./main.cc
> ./main
OK
Oo.oO
  • 12,464
  • 3
  • 23
  • 45
  • 2
    Hold on...are you asking me to include a Java file in C++ code ? Does cc extension allow that ? And `#define public` , is that legal code given that public is a keyword in C++ ? – Zoso Aug 02 '17 at 04:48