Cargar un recurso contenido en un jar
En mi aplicación cargo recursos de esta manera:
WinProcessor.class.getResource("repository").toString();
y esto me da:
file:/root/app/repository (and I replace "file:" with empty string)
Esto funciona bien cuando ejecuto mi aplicación desde el IDE, pero cuando ejecuto el jar de mi aplicación:
java -jar app.jar
El camino se convierte en:
jar:/root/app.jar!/repository
¿Hay alguna forma de solucionar este problema?
Usaré el nombre del directorio "repositorio" para crear esto:
ConfigurationContext ctx = (ConfigurationContext) ConfigurationContextFactory.createConfigurationContextFromFileSystem(repositoryString, null);
De la misma manera, obtendré un nombre de archivo (en lugar de un directorio) y lo usaré de esta manera:
System.setProperty("javax.net.ssl.trustStore", fileNameString)
Parece que estás intentando cargar el recurso usando FileInputStream
algo así. No hagas eso: en lugar de llamar getResource
, llama getResourceAsStream
y lee los datos de eso.
(En su lugar, podría cargar los recursos desde la URL, pero llamar getResourceAsStream
es un poco más conveniente).
EDITAR: Habiendo visto su respuesta actualizada, parece que otros fragmentos de código dependen de que los datos estén en un único archivo físico en el sistema de archivos. Por lo tanto, la respuesta es, en primer lugar, no agruparlo en un archivo jar. Puede verificar si está en un archivo separado y, si no, extraerlo a un archivo temporal, pero en mi opinión, eso es bastante complicado.
Cuando ejecuta código usando java -jar app.jar
, Java usa SÓLO la ruta de clase definida en el manifiesto del archivo JAR (es decir, Class-Path
atributo). Si la clase está en app.jar
, o la clase está en la ruta de clase establecida en el Class-Path
atributo del manifiesto del JAR, puede cargar esa clase usando el siguiente fragmento de código, donde es className
el nombre de clase completo.
final String classAsPath = className.replace('.', '/') + ".class";
final InputStream input = ClassLoader.getSystemResourceAsStream( path/to/class );
Ahora bien, si la clase no es parte del JAR y no está en el manifiesto Class-Path
, entonces el cargador de clases no la encontrará. En su lugar, puede utilizar URLClassLoader
, con cierto cuidado para abordar las diferencias entre Windows y Unix/Linux/MacOSX.
// the class to load
final String classAsPath = className.replace('.', '/') + ".class";
// the URL to the `app.jar` file (Windows and Unix/Linux/MacOSX below)
final URL url = new URL( "file", null, "///C:/Users/diffusive/app.jar" );
//final URL url = new URL( "file", null, "/Users/diffusive/app.jar" );
// create the class loader with the JAR file
final URLClassLoader urlClassLoader = new URLClassLoader( new URL[] { url } );
// grab the resource, through, this time from the `URLClassLoader` object
// rather than from the `ClassLoader` class
final InputStream input = urlClassLoader.getResourceAsStream( classAsPath );
En ambos ejemplos, deberá lidiar con las excepciones y el hecho de que el flujo de entrada es null
si no se puede encontrar el recurso. Además, si necesita ingresar InputStream
a byte[]
, puede usar los commons de Apache IOUtils.toByteArray(...)
. Y, si luego desea un archivo Class
, puede usar el defineClass(...)
método del cargador de clases, que acepta el archivo byte[]
.
Puede encontrar este código en una ClassLoaderUtils
clase en el código fuente de Diffusive, que puede encontrar en SourceForge en github.com/robphilipp/diffusive
Y un método para crear URL para Windows y Unix/Linux/MacOSX a partir de rutas relativas y absolutas enRestfulDiffuserManagerResource.createJarClassPath(...)
Construya un URL
, luego puede cargar un recurso (incluso en un archivo jar) usando el openStream
método.