JNI: Retornar um struct (objeto) de um código nativo em C para uma classe em Java

Olá pessoal. Tudo bem?

Estou com o seguinte problema…
Utilizo a biblioteca fprint para fazer leitura e comparação de impressões digitais. Esta biblioteca está em C, portanto estou utilizando JNI para me comunicar com ela.

Até ai sem problemas. As chamadas aos métodos e a utilização da biblioteca via JNI eu consigo fazer. Sempre que eu “leio” uma impressão digital, utilizando o fprint, é gerado um struct do C com as informações da impressão digital lida. Como se fosse um objeto, uma espécie de “template” da digital.

O problema aparece quando eu vou comparar os “templates”. Se eu comparar dois “templates” sem sair do C a biblioteca fprint se comporta da maneira esperada, dizendo se são a a mesma impressão digital ou não. Porém quando tento retornar este “template” para o Java e depois recuperá-lo novamente pelo C através da JNI, a comparação me retorna um erro dizendo que o “template” é inválido.

Presumo que haja perda de dados na ida ou na volta do JNI.

Alguém saberia me dizer como posso enviar estes “templates” (structs do C) para o Java sem que haja perda de dados. Alguma espécie de serialização ou algo parecido?

Desde já agradeço. Até.

Depois de três exaustivos dias tentando, finalmente eu consegui fazer! =)

Utilizei o princípio da serialização mesmo.

Na hora de mandar pro Java:

[code]void getJTemplate(JNIEnv *env, jobject jtemplate, struct fp_print_data *template) {
jclass classe = (*env)->GetObjectClass(env, jtemplate);

jmethodID mSetTam = (*env)->GetMethodID(env, classe, "setTam", "(I)V");
jmethodID mSetDados = (*env)->GetMethodID(env, classe, "setDados", "([B)V");

unsigned int tam = sizeof(*template) + template->length;
unsigned char *dados = malloc(tam);
memcpy(dados, template, tam);

jbyteArray jdados = (*env)->NewByteArray(env, tam);
(*env)->SetByteArrayRegion(env, jdados, 0, tam - 1, dados);

(*env)->CallVoidMethod(env, jtemplate, mSetTam, tam);
(*env)->CallVoidMethod(env, jtemplate, mSetDados, jdados);

return;

}[/code]

E na hora de pegar do Java:

[code]struct fp_print_data *getTemplate(JNIEnv *env, jobject jtemplate) {
jclass classe = (*env)->GetObjectClass(env, jtemplate);

jmethodID mGetTam = (*env)->GetMethodID(env, classe, "getTam", "()I");
jmethodID mGetDados = (*env)->GetMethodID(env, classe, "getDados", "()[B");
int tam = (int)(*env)->CallObjectMethod(env, jtemplate, mGetTam);
jbyteArray jdados = (jbyteArray)(*env)->CallObjectMethod(env, jtemplate, mGetDados);

unsigned char *dados = malloc(tam);
(*env)->GetByteArrayRegion(env, jdados, 0, tam, dados);

struct fp_print_data *template = malloc(tam);
memcpy(template, dados, tam);

return template;

}[/code]

Lembrando que em C o "char" tem 8 bits assim como o "byte" do Java. Portanto do lado do C usa-se um vetor de chars e do lado do Java usa-se um vetor de bytes.

Bem… fica ai como referência. Espero que ajude alguém.

Obrigado e até. =)

Opa.

Eu sei que o post é antigo, mas eu to tentando fazer algo parecido.

Eu um arquivo .so que eu preciso pra mandar e receber informações de um equipamento. Já tentarem fazer com JNI, mas como não se conhece o fonte desse so não deu muito certo.

Eu estou tentando fazer uma ponte com JNI, criar o meu .so que conversa com o java e com o .so do equipamento.

O equipamento me retorna uma struct com um monde de informação que eu preciso.

Dava pra você mostrar como fica a parte do java também e ou explicar um pouco melhor o código postado (nunca mexi com JNI, to estudando e ainda sou noob no assunto, fiz uns exemplos, mas básicos só mostradno retornos de tipos primitivos, e no máximo array).