How do I load one of the named resources from different jars in the classpath?
Let's say there is a jar main.jar
that depends on two other jars - dep1.jar
and dep2.jar
. Both dependencies are in the classpath in MANIFEST.MF from main.jar
. Each of the dependency jars has a directory foo
inside with a file bar.txt
inside:
dep1.jar
|
\--foo/
|
\--bar.txt
dep2.jar
|
\--foo/
|
\--bar.txt
Here is the main class main.jar
:
public class App
{
public static void main( String[] args ) {
ApplicationContext ctx = new StaticApplicationContext();
Resource barResource = ctx.getResource("classpath:foo/bar.txt");
}
}
Which of the two files bar.txt
will be downloaded? Is there a way to specify in the url of the jar resource from which the file should be loaded?
source to share
Flip the quarter over, the one you get. It will most likely be one of the highest in alphabetical order, so in your case, one inside dep1.jar. Both files have the same classpaths (foo.Bar), and while it should look like throwing a compile-time exception, this is not going to happen because it will just package both banks, and not try to compile / view the file (this particular file) since it is a file. txt.
source to share
You would not expect a compile-time exception, since resource loading is a run-time process.
You cannot specify which jar resource will come from the code and this is a common problem, especially when someone is linking something like log4j.properties in the jar file.
What you can do is specify the order of the jars in your classpath and it will take the resource from the first one in the list. This is tricky because when you use something like ivy or maven for the classpath dependencies, you have no control over the order in the classpath (in all eclipse plugins).
The only reliable solution is to name the resources something else, or put them in separate packages.
source to share
The spec states that the first class / resource on the classpath is accepted (AFAIK).
However, I would try:
Dep1Class.class.getResource("/foo/bar.txt");
Dep2Class.class.getResource("/foo/bar.txt");
Since Class.getResource cannot take resources from another jar, unlike the system class loader.
With a little luck, you won't need to play ClassLoader
around with and hava loading the loader of another dep2.jar class.
source to share
As @Sotirios said, you can get all resources with the same name using ctx.getResources(...)
code like this:
ApplicationContext ctx = new StaticApplicationContext();
Resource[] resources = ctx.getResources("classpath*:/foo/bar.txt");
for (Resource resource : resources) {
System.out.println("resource file: " + resource.getURL());
InputStream is = new FileInputStream(resource.getFile());
if (is == null) {
System.out.println("resource is null");
System.exit(-1);
}
Scanner scanner = new Scanner(is);
while(scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
source to share