Diferentes Formas de Acessar Bibliotecas Nativas em Java: JNI, JNA e FFM

Por Gaspar Barancelli Junior em 20 de julho de 2024
Imagem ilustrativa sobre o post Diferentes Formas de Acessar Bibliotecas Nativas em Java: JNI, JNA e FFM

No desenvolvimento Java, às vezes precisamos interagir com bibliotecas nativas escritas em linguagens como C ou C++. Atualmente se fala muito em inteligência artificial e machine learning, o acesso a bibliotecas nativas pode trazer benefícios significativos, como:

  • Desempenho: As bibliotecas nativas podem executar operações de baixo nível de maneira mais eficiente do que o código Java puro, aproveitando otimizações específicas da arquitetura do processador.

  • Reutilização de Código: Muitas bibliotecas e frameworks estabelecidos, especialmente em áreas como IA e ML, estão disponíveis apenas em linguagens como C e C++. Usar essas bibliotecas pode evitar a necessidade de reescrever funcionalidades complexas em Java.

  • Interoperabilidade: Permite que aplicativos Java se integrem com sistemas e APIs que foram desenvolvidos em outras linguagens, ampliando as capacidades do software.

A seguir, vamos explorar três principais maneiras de acessar bibliotecas nativas em Java: JNI (Java Native Interface), JNA (Java Native Access) e a mais recente API FFM (Foreign Function & Memory API).

JNI (Java Native Interface)

Visão Geral:

JNI é uma interface poderosa e de baixo nível que permite ao código Java chamar funções nativas e vice-versa. Embora ofereça alto desempenho, a sua complexidade e necessidade de código nativo compilado tornam-no mais difícil de usar.

Exemplo de Uso:

Criação do Método Java Nativo:
public class HelloWorldJNI {
    static {
        System.loadLibrary("helloworld");
    }

    private native int strlen(String str);

    public static void main(String[] args) {
        HelloWorldJNI instance = new HelloWorldJNI();
        int length = instance.strlen("https://gasparbarancelli.com");
        System.out.println("length: " + length);
    }
}
Geração do Cabeçalho JNI:
javac HelloWorldJNI.java
javah -jni HelloWorldJNI
Implementação da Função Nativa (C/C++):
#include <jni.h>
#include "HelloWorldJNI.h"
#include <string.h>

JNIEXPORT jint JNICALL Java_HelloWorldJNI_strlen(JNIEnv *env, jobject obj, jstring str) {
    const char *nativeString = (*env)->GetStringUTFChars(env, str, 0);
    jint length = strlen(nativeString);
    (*env)->ReleaseStringUTFChars(env, str, nativeString);
    return length;
}
Compilação do Código Nativo:
gcc -shared -o libhelloworld.so -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux HelloWorldJNI.c
Execução do Programa Java:
java -Djava.library.path=. HelloWorldJNI
Nota sobre JNI e JEP 472:

O JEP 472 propõe restringir o uso de JNI devido a questões de segurança e manutenção. A proposta destaca que JNI permite acesso direto à memória, o que pode causar problemas de segurança e estabilidade na JVM. A restrição ao uso de JNI incentiva a adoção de APIs mais seguras e modernas como o FFM.

JNA (Java Native Access)

Visão Geral:

JNA simplifica o acesso a bibliotecas nativas, eliminando a necessidade de escrever código nativo. Ele mapeia automaticamente funções nativas para interfaces Java, facilitando a integração.

Exemplo de Uso:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class HelloWorldJNA {

    public interface CLibrary extends Library {
        CLibrary INSTANCE = Native.load((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
        long strlen(String str);
    }

    public static void main(String[] args) {
        long length = CLibrary.INSTANCE.strlen("https://gasparbarancelli.com");
        System.out.println("length: " + length);
    }

}

Para usar JNA, adicione a seguinte dependência no seu pom.xml:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.14.0</version>
</dependency>

Mais informações sobre JNA podem ser encontradas no repositório GitHub do JNA.

FFM (Foreign Function & Memory API)

Visão Geral:

FFM é uma API moderna introduzida no projeto Panama, projetada para oferecer uma maneira segura e eficiente de interagir com bibliotecas nativas e acessar memória nativa. É a abordagem mais recente e promissora, onde a release final foi liberada no Java 22.

Exemplo de Uso:

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_LONG;

public class HelloWorldFFM {

    public static void main(String[] args) throws Throwable {
        SymbolLookup stdlib = Linker.nativeLinker().defaultLookup();
        MethodHandle strlen = Linker.nativeLinker().downcallHandle(
                stdlib.find("strlen").orElseThrow(),
                FunctionDescriptor.of(JAVA_LONG, ADDRESS));

        try (Arena offHeap = Arena.ofConfined()) {
            MemorySegment str = offHeap.allocateFrom("https://gasparbarancelli.com");
            long length = (long) strlen.invoke(str);
            System.out.println("length: " + length);
        }
    }

}

O FFM é mais seguro em relação ao uso de memória, pois utiliza o conceito de MemorySegment e Arena, para gerenciar a memória nativa de forma segura.

  • MemorySegment: É uma abstração sobre a memória nativa que oferece segurança e controle sobre os dados alocados fora do heap Java.

  • Arena: É um mecanismo para alocação e gerenciamento de memória que garante que os recursos sejam liberados corretamente, evitando vazamentos de memória.

Para mais detalhes, consulte a documentação oficial.

Conclusão

As três abordagens — JNI, JNA e FFM — oferecem diferentes níveis de controle, facilidade de uso e desempenho para interagir com bibliotecas nativas em Java. JNI é ideal para situações que requerem controle e desempenho máximo, embora seja mais complexo e venha a ser restringido pelo JEP 472. JNA simplifica muito a integração com código nativo, sendo excelente para a maioria dos casos de uso. FFM é uma abordagem moderna e promissora, oferecendo segurança e eficiência, e deve ser considerada para novos projetos.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×