La bibliothèque en question est Cabinet de Tokyo .
Je souhaite disposer de la bibliothèque native, de la bibliothèque JNI et de toutes les Java de l'API dans un fichier JAR pour éviter les problèmes de redistribution.
Il semble y avoir ne tentative de ceci à GitHub , mais
La question est de savoir si je peux tout regrouper dans un fichier JAR et le redistribuer. Si oui comment?
P.S .: Oui, je me rends compte que cela peut avoir des implications sur la portabilité.
Il est possible de créer un seul fichier JAR avec toutes les dépendances, y compris les bibliothèques JNI natives pour une ou plusieurs plates-formes. Le mécanisme de base consiste à utiliser System.load (File) pour charger la bibliothèque à la place de System.loadLibrary (String), qui recherche la propriété système Java.library.path. Cette méthode simplifie beaucoup l'installation car l'utilisateur n'a pas à installer la bibliothèque JNI sur son système, mais toutes les plates-formes risquent de ne pas être prises en charge, car la bibliothèque spécifique d'une plate-forme peut ne pas être incluse dans le fichier JAR unique. .
Le processus est le suivant:
J'ai ajouté une fonctionnalité permettant de faire cela pour jzmq, les liaisons Java de ZeroMQ (plug sans vergogne)). Le code est disponible ici . Le code jzmq utilise une solution hybride que si une bibliothèque incorporée ne peut pas être chargée, le code reprendra la recherche de la bibliothèque JNI le long de Java.library.path.
https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/
est un excellent article, qui résout mon problème ..
Dans mon cas, j'ai le code suivant pour initialiser la bibliothèque:
static {
try {
System.loadLibrary("crypt"); // used for tests. This library in classpath only
} catch (UnsatisfiedLinkError e) {
try {
NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}
}
Jetez un oeil à One-JAR . Il encapsulera votre application dans un fichier JAR unique avec un chargeur de classe spécialisé, qui gère notamment les "fichiers JAR dans les fichiers JAR".
Il gère les bibliothèques natives (JNI) en les décompressant dans un dossier de travail temporaire, selon les besoins.
(Avertissement: je n'ai jamais utilisé One-JAR, je n'ai pas encore eu besoin de le faire, je l'ai simplement mis en favori pour un jour de pluie.)
JarClassLoader est un chargeur de classes permettant de charger des classes, des bibliothèques natives et des ressources à partir d'un seul JAR monstre et de JAR situés à l'intérieur du JAR monstre.
1) Incluez la bibliothèque native dans votre fichier JAR en tant que ressource. Par exemple. avec Maven ou Gradle et la structure de projet standard, place la bibliothèque native dans main/resources
répertoire.
2) Quelque part dans les initialiseurs statiques de Java classes, liées à cette bibliothèque, mettez le code comme suit:
String libName = "myNativeLib.so"; // The name of the file in resources/ dir
URL url = MyClass.class.getResource("/" + libName);
File tmpDir = Files.createTempDirectory("my-native-lib").toFile();
tmpDir.deleteOnExit();
File nativeLibTmpFile = new File(tmpDir, libName);
nativeLibTmpFile.deleteOnExit();
try (InputStream in = url.openStream()) {
Files.copy(in, nativeLibTmpFile.toPath());
}
System.load(nativeLibTmpFile.getAbsolutePath());
Vous devrez probablement libérer la bibliothèque native du système de fichiers local. Autant que je sache, le code utilisé par le chargement natif concerne le système de fichiers.
Ce code devrait vous aider à démarrer (je ne l'ai pas lu depuis un moment et il a un but différent, mais devrait faire l'affaire, et je suis plutôt occupé pour le moment, mais si vous avez des questions, laissez un commentaire. et je répondrai dès que possible).
import Java.io.Closeable;
import Java.io.File;
import Java.io.FileNotFoundException;
import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.OutputStream;
import Java.io.UnsupportedEncodingException;
import Java.net.URI;
import Java.net.URISyntaxException;
import Java.net.URL;
import Java.net.URLDecoder;
import Java.security.CodeSource;
import Java.security.ProtectionDomain;
import Java.util.Zip.ZipEntry;
import Java.util.Zip.ZipException;
import Java.util.Zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}