2010-05-30 15 views
84

La biblioteca en cuestión es Tokyo Cabinet.¿Cómo agrupar una biblioteca nativa y una biblioteca JNI dentro de un JAR?

Lo que quiero es tener la biblioteca nativa, la biblioteca JNI y todas las clases API de Java en un solo archivo JAR para evitar dolores de cabeza de redistribución.

No parece haber an attempt at this at GitHub, pero

  1. No incluye la biblioteca nativa real, única biblioteca JNI.
  2. Parece ser específico del complemento de dependencias nativas de Leiningen (no funcionará como una redistribución).

La pregunta es, ¿puedo agrupar todo en un JAR y redistribuirlo? Si es así, ¿cómo?

P.S .: Sí, me doy cuenta de que puede tener implicaciones de portabilidad.

Respuesta

1

Es probable que deba destrabar la biblioteca nativa en el sistema de archivos local. Por lo que sé, el bit de código que hace la carga nativa se ve en el sistema de archivos.

Este código debería ayudarlo a comenzar (no lo he visto desde hace tiempo, y es para un propósito diferente, pero debería ser el truco, y estoy bastante ocupado en este momento, pero si tiene preguntas) solo deja un comentario y te responderé tan pronto como pueda).

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(); 
      } 
     } 
    } 
} 
+1

Si necesita alguna unjar recurso específico, recomiendo echar un vistazo a https://github.com/zeroturnaround/zt-zip project –

+0

zt-zip parece una API decente. – TofuBeer

17

Eche un vistazo a One-JAR. Envolverá su aplicación en un único archivo jar con un cargador de clases especializado que maneja "jarras dentro de jarras", entre otras cosas.

Es handles native (JNI) libraries desempaquetando en una carpeta de trabajo temporal según sea necesario.

(Negación:. Nunca he usado una sola JAR, no han necesitado hasta ahora, sólo tenía que bien marcado por un día lluvioso)

+0

No soy un programador de Java, ¿alguna idea si tengo * para envolver la aplicación en sí? ¿Cómo funcionaría esto en combinación con un cargador de clases existente? Para aclararlo, voy a usarlo de Clojure y quiero poder cargar un JAR como una biblioteca, en lugar de como una aplicación. –

+0

Ahhh, probablemente no sería adecuado que. Piensa que se verá obligado a distribuir su (s) biblioteca (s) nativa (s) fuera del archivo jar, con instrucciones para ponerlas en la ruta de la biblioteca de la aplicación. – Evan

5

JarClassLoader es un cargador de clases para cargar clases, bibliotecas nativas y recursos de un solo monstruo JAR y de JAR dentro del monstruo JAR.

29

https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/

es gran artículo, que resuelve mi problema ..

En mi caso tengo el siguiente código para inicializar la biblioteca:

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); 
     } 
    } 
} 
+17

use NativeUtils.loadLibraryFromJar ("/ natives /" + System.mapLibraryName ("crypt")); podría ser mejor – BlackJoker

+0

¡Buen punto!gracias – davs

+1

Hola cuando estoy tratando de usar la clase NativeUtils y tratando de alojar el archivo .so dentro de las libs/armeabi/libmyname.so, estoy recibiendo la excepción como java.lang.ExceptionInInitializerError, Causado por: java.io .FileNotFoundException: File /native/libhellojni.so no se encontró dentro de JAR. Por favor, hágame saber por qué recibo la excepción. Gracias – Ganesh

Cuestiones relacionadas