views:

65

answers:

3

Given:

enum Foo
{
  FIRST,
  SECOND
}

What is the JNI equivalent for the following code?

Foo foo = ...;
int value;
switch (foo)
{
  case FIRST:
    value = 1;
    break;
  case SECOND:
    value = 2;
    break;
}

I know I can use foo.equals(Foo.FIRST) from JNI, but I'd like to get the same performance as switch(enum). Any ideas?

A: 

What you're referring as value is actually the ordinal of the enum

To achieve value fetching, simple store it as a private field in you FooEnum:

public enum FooEnum {
   private final int value;

   private FooEnum(int value) {
       this.value = value;
   }

   public int getValue() {
      return value;
   }

   FIRST(1);
}

This way you can switch based on your FooEnum value.

Bivas
Why is FooEnum declared above as a class rather than an enum?
Andy Thomas-Cramer
By mistake, i wrote it with old-style enum
Bivas
A: 

You can use a switch statement in your JNI code as well, if you:

  • Provide an integral value field in your Java enum class.
  • Define a parallel set of integral constants in C or C++ (e.g., by another enum).

The redundant definition introduces a risk of divergence. You can mitigate this by:

  • Heavily documenting the parallelism on both sides. This works best if the enumeration is small and changes infrequently.
  • Generating the code from a single source.

For example, in Java, you could have:

    public enum Foo {
            FIRST(0),
            SECOND(1);

            public int getValue() { return m_value; }

            private int m_value;
            private Foo( int value ) { m_value = value; }
    }

And in C++, you could have:

    enum Foo {
          FIRST = 0,
          SECOND = 1
    };

For a parallel enumeration, I personally always make the enum values explicit on the C/C++ side. Otherwise, a deletion of an enumerator on both sides can cause the values to diverge.

Andy Thomas-Cramer
+1  A: 

You could have a process step that runs after the enum is compiled but before the JNI code is compiled. It would load the enum and output the values to a .h file. Your JNI code then includes this .h file.

Edit:

Here's some code that does this. It needs to be modified to accept arguments and to write to a file instead of System.out, but that's easy enough to do.

    URL u = new File("/home/adam/tmp").toURL();
    URLClassLoader loader = new URLClassLoader(new URL[] {u}, Test.class.getClassLoader());
    Class<? extends Enum> c = (Class<? extends Enum>) loader.loadClass("Color");
    PrintStream out = System.out;
    out.println("#ifndef COLOR_H");
    out.println("#define COLOR_H");
    for(Enum constant : c.getEnumConstants()) {
        out.println("#define " + c.getCanonicalName().replaceAll("\\.", "_") + "_" + constant.name() + " " + constant.ordinal());
    }
    out.println("#endif");
Adam Crume
I've implemented your proposal in Jace: https://sourceforge.net/projects/jace/
Gili
Glad I could help.
Adam Crume
You don't need it. Javah already does exactly that.
EJP
@EJP: I tried that. Is there a flag you can give it to make it work? Otherwise, it just creates prototypes for native methods.
Adam Crume
Last time I did it it just worked. Have a look at your .h and .c files.
EJP