6

I am working with JNI and I have to pass in some generic types to the C++. I am stuck with how to approach this on the C++ side

HashMap<String, Double[]> data1 ; 
ArrayList<ArrayList<String>> disc ;

I am new to JNI and looked around but could not find much help. Can some one help me how to write JNI code for this please. Any reference to material on the net would be very helpful too.

sth
  • 222,467
  • 53
  • 283
  • 367
dcmovva
  • 155
  • 1
  • 3
  • 10
  • 1
    You can't pass parametrized generics to C++ via JNI. Generics are implemented via type erasure (where generics are stripped of generic parameters, ending up as plain old pre-Java 5 classes and containers.) – luis.espinal Apr 12 '11 at 21:00
  • To which native types are you trying to convert? – Asaf Apr 12 '11 at 21:13

3 Answers3

9

Short answer: You cannot.

Long answer: Type Erasure : http://download.oracle.com/javase/tutorial/java/generics/erasure.html

Consider a parametrized instance of ArrayList<Integer>. At compile time, the compiler checks that you are not putting anything but things compatible to Integer in the array list instance.

However, also at compile time (and after syntactic checking), the compiler strips the type parameter, rendering ArrayList<Integer> into Arraylist<?> which is equivalent to ArrayList<Object> or simply ArrayList (as in pre JDK 5 times.)

The later form is what JNI expects (because of historical reasons as well as due to the way generics are implemented in Java... again, type erasure.)

Remember, an ArrayList<Integer> is-a ArrayList. So you can pass an ArrayList<Integer> to JNI wherever it expects an ArrayList. The opposite is not necessarily true as you might get something out of JNI that is not upwards compatible with your nicely parametrized generics.

At this point, you are crossing a barrier between a typed, parametrized domain (your generics) and an untyped one (JNI). You have to encapsulate that barrier pretty nicely, and you have to add glue code and error checking/error handling code to detect when/if things don't convert well.

luis.espinal
  • 10,331
  • 6
  • 39
  • 55
  • What about ` void someMethod(T arg)`? I tried to call `GetMethodID()` for this method but failed with "Ljava/lang/Object;" and "Ldd/ee/SomeOtherInterface;", but succeeded with "Laa/bb/SomeInterface;". Both are `interface`s. Could you explain about this, please? – Jenix Feb 05 '19 at 19:32
7

The runtime signature is just plain HashMap and ArrayList - Generics are a compile-time thing.

You can use javah to generate a C header file with correct signatures for native functions.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • I did. They came out as jobject. I tried making calls to methods keySet etc. They gave me Method not found exceptions. But then I was not sure if I need to call methods on them. May be there is a way to just read that data in. – dcmovva Apr 12 '11 at 21:01
  • You'll need to get a jclass for HashMap and then get a method ID for keySet, and then call it. You'll likely make your life a lot easier by passing arrays in though. – Erik Apr 12 '11 at 21:03
  • This is what I have so far jclass cls = env ->GetObjectClass(irData) ; jmethodID mGetValue = env->GetMethodID(cls, "keySet","()Ljava/util/Set;"); if(mGetValue == NULL){ return ; } jobject value = env->CallObjectMethod(irData, mGetValue); – dcmovva Apr 12 '11 at 21:07
  • There's no generics runtime - remove the `` part. – Erik Apr 12 '11 at 21:08
  • Also, you can call `env->ExceptionOccurred()` `env->ExceptionDescribe()` and `env->ExceptionClear()` to manage any exceptions thrown. – Erik Apr 12 '11 at 21:11
0

It depends on what you're trying to map to and if they are yours to change.

Here are a few directions I'd try to go about (if i were you, that is :) ):

  1. Using SWIG templates (related SO question) or TypeMaps.
  2. Doing some reflection magic to be used against your-own-custom-generic-data-passing native API (haven't figured the details out, but if you want to follow on it, tell what you've got on the C++ side).

This has been asked before and you might want to resort to Luis' arrays solution.

Community
  • 1
  • 1
Asaf
  • 2,480
  • 4
  • 25
  • 33