2010-02-09 29 views
5

¿Es posible llamar a una función CPP nativa usando JNI que toma argumentos genéricos? Algo así como lo siguiente:Java genéricos y JNI

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

Y luego llamar así:

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

Puede alguien por favor me proporcione una muestra que en realidad está haciendo esto o algún tutorial en la red que hace esto? Lo estoy preguntando porque en mi función CPP JNI (llamada por JVM), obtengo un error de enlace insatisfecho.

Código CPP sigue:

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:

He tratado mediante la modificación del código, pero ahora estoy consiguiendo NoSuchMethodError:

código

Java:

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

CPP code:

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); 
} 

¿Esto significa que JNI no tiene soporte para los genéricos o me falta algo?

+1

JNI no hace nada mágico. Al igual que con el código Java estándar de pantano, ¿de dónde crearías una 'T'? –

Respuesta

7

Existen numerosas preguntas sobre el borrado de tipos en el desbordamiento de la pila (por ejemplo, Get generic type of java.util.List), lo que está buscando hacer tampoco es posible con JNI ni con la propia Java. La firma del tipo de tiempo de ejecución de foo es (en ambos mundos, o en realidad, hay un solo mundo) Object foo(Object u, Object v), lo que hará una conversión de clase implícita en el valor de retorno al tipo con el que lo llame.

Como probablemente haya notado (y como se menciona en el comentario de su pregunta), no hay manera de que sepa qué tipo es T.

EDITAR:
Por cierto, se supone que el método getFoo para volver 'Foo', por lo que no debería estar haciendo que

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

Ahora que lo pienso de ella, la secuencia de llamada entera parece fuera de lugar ... tienes un foo que es nativo y devuelve cadena. Ahora foo busca getFoo en Bar, que devuelve 'Foo', y devuelve el resultado de esa llamada directamente, tratando efectivamente de devolver un Foo (Foo getFoo() según el comentario) donde se espera la cadena.

8

En general, siempre debe usar javap -s para obtener las firmas de los métodos que va a buscar en JNI. No adivine

+2

No estoy de acuerdo. Mi biblioteca nativa tiene 51 funciones y las codifiqué a mano todas sin problemas. Realmente no es nada difícil hacerlas bien si solo te paras y piensas por un minuto sobre lo que estás haciendo. –

+3

¿Pero por qué correr * cualquier * riesgo, cuando tienes una herramienta que ya es 100% correcta? – EJP

+2

'javah' tomará un archivo de clase y generará un archivo de encabezado C que contiene las funciones exactas que necesita para implementar –