I have a simple structure: A data jar file which contains a batch of data, and a service jar file, which runs a service using the data. To make the data easy to replace, I have them separate, and service.jar's classpath contains the directory which data.jar is in.
Within service.jar, I use getResource to load the data files. This works if the data files are directly within the folder, but fails when they are inside data.jar;
This fails:
all
+ globalclasspath
| + data.jar
| + mine.properties
+ daemons
+ service.jar
jsvc -cp globalclasspath:daemons/service.jar (...)
MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- null
But this works:
all
+ globalclasspath
| + mine.properties
+ daemons
+ service.jar
jsvc -cp globalclasspath:daemons/service.jar (...)
MyClass.class.getClassLoader( ).getResource( "mine.properties" ); // <-- not null
I don't want to change the classpath (unless I can change it to something generic which doesn't depend on the name of the data jar file), but I'm fine with changing the getResource string (I've tried /data/mine.properties and /data.jar/mine.properties to no avail). Is there a change I can make so that the resources can be loaded from within the jar?
A JAR file can contain anything you want, but the same limitation is there: the system class loader can't load classes that are in a JAR inside a JAR.
What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir. After that you can concat the dir path with each file name and call getResourceAsStream for each file in a loop.
1) click project -> properties -> Build Path -> Source -> Add Folder and select resources folder. 2) create your JAR! EDIT: you can make sure your JAR contains folder by inspecting it using 7zip.
Solution 1
Use a classpath wildcard.
jsvc -cp globalclasspath/*:daemons/service.jar (...)
See "How to use a wildcard in the classpath to add multiple jars?"
Solution 2
To read data in JARs not on the classpath, use URLClassLoader
. The general algorithm is this:
globalclasspath
directory.URLClassLoader
from this list of JARs.URLClassLoader
instance.To find JARs on the classpath, I used ResourceList
from the StackOverflow article "Get a list of resources from classpath directory."
public class MyClass {
/**
* Creates a {@code URLClassLoader} from JAR files found in the
* globalclasspath directory, assuming that globalclasspath is in
* {@code System.getProperty("java.class.path")}.
*/
private static URLClassLoader createURLClassLoader() {
Collection<String> resources = ResourceList.getResources(Pattern.compile(".*\\.jar"));
Collection<URL> urls = new ArrayList<URL>();
for (String resource : resources) {
File file = new File(resource);
// Ensure that the JAR exists
// and is in the globalclasspath directory.
if (file.isFile() && "globalclasspath".equals(file.getParentFile().getName())) {
try {
urls.add(file.toURI().toURL());
} catch (MalformedURLException e) {
// This should never happen.
e.printStackTrace();
}
}
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]));
}
public static void main(String[] args) {
URLClassLoader classLoader = createURLClassLoader();
System.out.println(classLoader.getResource("mine.properties"));
}
}
I ran the following command:
java -cp globalclasspath:daemons/service.jar MyClass
The terminal output:
jar:file:/workspace/all/globalclasspath/data.jar!/mine.properties
Have you tried getResourceAsStream
as suggested here:
how-to-a-read-file-from-jar-in-java
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With