quarta-feira, 12 de fevereiro de 2014

java.lang.UnsatisfiedLinkError

O erro java.lang.UnsatisfiedLinkError é lançado quando se carrega uma uma DLL pelo java.lang.System.loadLibrary("mylibrary"). O problema pode ocorrer porque a JVM não consegue localizar o arquivo a ser carregado, conforme mostrado abaixo.

Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylibrary in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)
    at java.lang.Runtime.loadLibrary0(Runtime.java:823)
    at java.lang.System.loadLibrary(System.java:1028)

Pesquisando na internet, logo se descobre que é necessário adicionar o caminho da DLL na variável de java.library.path. Para tanto, o aplicativo deveria ser inicializado assim:

java -Djava.library.path=/path/to/my/dll -jar application.jar

... além de outros argumentos para iniciar corretamente a aplicação Java.

Iniciar um aplicativo desta forma não é nada amigável. Ainda, existem outros casos que o caminho e até o nome da DLL precisam ser resolvidos dinamicamente (este era o meu caso).

Além da incialização da variável por linha de comando, existem várias outras soluções para o problema, como colocar a DLL num caminho que já esteja definido no java.library.path ou mesmo num caminho definido na variável de ambiente PATH (no Windows) do sistema operacional.

Todavia, alterar a variável java.library.path por código Java é uma opção mais viável e muito mais fácil. Esta informação não é nenhuma novidade e facilmente se encontra esta codificação pela Internet:

String javaLibPath = System.getProperty("java.library.path");
javaLibPath += ";" + newPath;
System.setProperty("java.library.path", javaLibPath); 

Uma vez a variável alterada pelo código do programa, antes do carregamento da DLL, se espera que o problema seja resolvido. Mas não, o erro UnsatisfiedLinkError continua aparecendo!

O problema persiste porque a JVM faz a leitura da variável na java.library.path na inicialização do aplicativo e atribui seus valores à uma outra variável interna chamada de  sys_paths. Mesmo que a variável java.library.path seja alterada posteriormente, a JVM não atualiza a sua variável interna.

Para fazer com que a JVM atualize novamente a sys_paths, o código abaixo precisa ser adicionado, após o código descrito anteriormente, para alterar o java.library.path:

final Field field = ClassLoader.class.getDeclaredField("sys_paths");
field.setAccessible(true);
field.set(null, null);

No próximo instante que a JVM fizer uso da sua variável interna sys_paths, estando ela com valor nulo, ela será então reiniciada com os valores da variável java.library.path.

Os créditos desta dica ficam para Fahd Shariff, autor do artigo Changing JavaLibrary Path at Runtime.

Nenhum comentário:

Postar um comentário