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

2 respostas
D

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é.

2 Respostas

D

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:
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;
}
E na hora de pegar do Java:
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;
}

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é. =)

rock-skull

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).

Criado 11 de julho de 2008
Ultima resposta 22 de jul. de 2011
Respostas 2
Participantes 2