2010-02-09 7 views
5

Czy można wywołać natywną funkcję CPP za pomocą JNI, która pobiera ogólne argumenty? Coś jak następuje:Java generics i JNI

public static native <T, U, V> T foo(U u, V v); 

a następnie wywołać to lubią:

//class Foo, class Bar, class Baz are already defined; 
Foo f = foo(new Bar(), new Baz()); 

Może ktoś proszę podać mnie z próbką, która jest faktycznie robi to albo jakiś tutorial na sieci, która to robi? Pytam, ponieważ w mojej funkcji CPNI JNI (wywoływanej przez JVM) pojawia się niezadowalający błąd łącza.

Kod CPP następująco:

JNIEXPORT jobject JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2) 
{ 
    jclass bar_class = env->FindClass("Bar"); 
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/Object;"); 
//getFoo() is defined as `public Foo getFoo();` in Bar.java 
    return env->CallObjectMethod(obj1, getFooMethod); 
} 

EDIT:

Próbowałem, modyfikując kod, ale teraz jestem coraz NoSuchMethodError:

kod

Java:

public static native <U, V> String foo(U u, V v); 
//... 
String str = foo(new Bar(), new Baz()); 

Kod CPP:

JNIEXPORT jstring JNICALL Java_Processor_process (JNIEnv *env, jclass processor_class, jobject obj1, jobject obj2) 
{ 
    jclass bar_class = env->FindClass("Bar"); 
    jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()Ljava/lang/String;"); 
    //getFoo() is now defined as `public String getFoo();` in Bar.java 
    return env->CallObjectMethod(obj1, getFooMethod); 
} 

Czy to oznacza, że ​​JNI nie ma wsparcia dla leków generycznych lub czegoś brakuje?

+1

JNI nie robi nic magicznego. Podobnie jak w przypadku standardowego kodu Javy, gdzie utworzysz 'T'? –

Odpowiedz

7

Istnieje wiele pytań dotyczących wymazywania typu na przepełnieniu stosu (np. Get generic type of java.util.List), a tego, czego szukasz, nie jest możliwe z JNI ani z samą Javą. Sygnatura typu środowiska wykonawczego foo jest (w obu światach lub w rzeczywistości jest tylko jeden świat) Object foo(Object u, Object v), która wykona niejawną rzutowanie klasy na wartość zwracaną do dowolnego typu, z którym ją wywołujemy.

Jak można zauważyć (i jak wspomniano w komentarzu do pytania), nie ma sposobu, aby dowiedzieć się, jaki typ jest T.

EDIT:
Nawiasem mówiąc, metoda getFoo ma powrócić „foo”, więc nie należy robić

jmethodID getFooMethod = env->GetMethodID(bar_class, "getFoo", "()LFoo;"); 

Przyjdź, aby myśleć o tym, cała sekwencja połączeń wydaje nie na miejscu ... masz foo, który jest natywnym, powracającym łańcuchem. Teraz foo szuka getFoo w Bar, który zwraca "Foo", i zwraca wynik tego połączenia bezpośrednio, skutecznie próbując zwrócić Foo (Foo getFoo() zgodnie z komentarzem), gdzie oczekiwany jest łańcuch.

8

Generalnie zawsze powinieneś używać javap -s, aby uzyskać sygnatury metod, których będziesz szukał w JNI. Nie zgaduj.

+2

Nie zgadzam się. Moja natywna biblioteka ma 51 funkcji i ręcznie je wszystkie bez problemów. Naprawdę wcale nie jest trudno je naprawić, jeśli po prostu przestaniesz zastanawiać się przez chwilę nad tym, co robisz. –

+3

Ale dlaczego uruchomić * dowolne * ryzyko, gdy masz narzędzie, które jest już w 100% poprawne? – EJP

+2

'javah' pobierze plik klasy i wypisze plik nagłówka C zawierający dokładne funkcje potrzebne do implementacji –