Load a resource contained in a jar
In my application I load resources in this manner:
WinProcessor.class.getResource("repository").toString();
and this gives me:
file:/root/app/repository (and I replace "file:" with empty string)
This works fine when I run my application from the IDE, but when I run the jar of my application:
java -jar app.jar
The path becomes:
jar:/root/app.jar!/repository
is there any way to solve this problem?
I'll use the "repository" dir name in order to create this:
ConfigurationContext ctx = (ConfigurationContext) ConfigurationContextFactory.createConfigurationContextFromFileSystem(repositoryString, null);
In the same manner, I'll get one file name (instead of a dir) and I'll use it this way:
System.setProperty("javax.net.ssl.trustStore", fileNameString)
Solution 1:
It sounds like you're then trying to load the resource using a FileInputStream
or something like that. Don't do that: instead of calling getResource
, call getResourceAsStream
and read the data from that.
(You could load the resources from the URL instead, but calling getResourceAsStream
is a bit more convenient.)
EDIT: Having seen your updated answer, it seems other bits of code rely on the data being in a physical single file in the file system. The answer is therefore not to bundle it in a jar file in the first place. You could check whether it's in a separate file, and if not extract it to a temporary file, but that's pretty hacky IMO.
Solution 2:
When running code using java -jar app.jar
, java uses ONLY the class path defined in the manifest of the JAR file (i.e. Class-Path
attribute). If the class is in app.jar
, or the class is in the class path set in the Class-Path
attribute of the JAR's manifest, you can load that class using the following code snippet, where the className
is the fully-qualified class name.
final String classAsPath = className.replace('.', '/') + ".class";
final InputStream input = ClassLoader.getSystemResourceAsStream( path/to/class );
Now if the class is not part of the JAR, and it isn't in the manifest's Class-Path
, then the class loader won't find it. Instead, you can use the URLClassLoader
, with some care to deal with differences between windows and 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 );
In both examples you'll need to deal with the exceptions, and the fact that the input stream is null
if the resource can't be found. Also, if you need to get the InputStream
into a byte[]
, you can use Apache's commons IOUtils.toByteArray(...)
. And, if you then want a Class
, you can use the class loader's defineClass(...)
method, which accepts the byte[]
.
You can find this code in a ClassLoaderUtils
class in the Diffusive source code, which you can find on SourceForge at github.com/robphilipp/diffusive
And a method to create URL for Windows and Unix/Linux/MacOSX from relative and absolute paths in RestfulDiffuserManagerResource.createJarClassPath(...)
Solution 3:
Construct a URL
, you can then load a resource (even in a jar file) using the openStream
method.