• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Spring cannot find file in classpath (within JAR)

 
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm stumped rigth now by some strange behavior by Spring's resource locations in my main project. I've made a smaller, simpler Spring projet to replicate my problem and I can't get it to work (ie: I've got the same problem as my main project).

Basically, I'm using a JAR file to stock all non-class files, which includes the spring xml bean configuration, and other files (text ones). I'm also using Eclipse as an IDE, if that could be the source of the problem.

Steps are this:
I got a bean class that is resource loader aware. It has two properties, one string and one Resource. It also got an init method once all properties are set. It should be able the get a resource from it's resourceLoader using the String property. However, Spring is not even able to create the Resource property using the file name I give it.
All files I try to get are located in the same JAR as the spring bean XML. The thing is, since Spring breaks during the bean instanciation, that should mean the JAR is accessible and that the files within it are accessible as well.
But, for all my tests, both files in the JAR (besides the XML) remain invisible to Spring.

Here is the source code for all classes:

Main class:


Bean class:


The Spring bean configuration XML:


The JAR file "fichier.jar" is in the classpath during execution and contains the following files:


Here is an error message that I get when I try to execute the main class:


Any help would be appreciated. Thanks in advance.

(Edit: inserted line breaks in extremely long stack-trace lines to make post a reasonable width -- Paul C)
 
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well it definitely finds the config.xml, so you know that it is reading in the jar file. But is it possible that the other file is in a subdirectory in the jar file.

Open the jar file in an app like WinZip or 7Zip and go to the far right to see the path of the file. Let us know what that path shows.

Also just as a test, try putting a "/" in the config file for the location of the test2.txt

like

classpath:/test2.txt

Just a test, not sure if it will help.

Mark
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hidden way over there in the far right of the error message, three screens to the right with the horizontal scroll bar, is this
fragment:

cannot be resolved to absolute file path because it does not reside in the file system


And you're getting a FileNotFoundException. So something in the bean creation is under the mistaken impression that you
are giving it a file name. Perhaps that's because of line 17 in your bean class which calls a getFile() method? I'm just guessing,
I know very little about Spring.
 
François Coupal
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I tried to put the text file location as this in the config.xml: "classpath:/test2.txt" (same for the other), but the error message is exactly the same (ie: the last part of the URL reads as fichiers.jar!/test2.txt, same as before).

I should have mentioned it clearly in the original post, but the three files are at the root of the "fichiers.jar" archive. In the original project that was not the case, but I quickly found with this test that it did not matter either way, as Spring did not manage to find it.

As for your question Paul, the stacktrace shows that the error occurs during Spring bean initialisation, and not in the class itself. Even then, the whole point of this little project is to act like a test case, it must not fail anywhere because it mimics the desired outcome, which is to have access to the files from within the class for further use, from resources given by Spring.

A few things I noticed since yesterday:
1- In the end of the output the last three lines show that the bean methods were called (#setResource, #init, etc...). I'll do more tests in those method to test the output, just in case the error message was a false positive.
2- Earlier tests (in the original project) showed that files in the root directory or in specific locations (file system) did work. However, this is not a desirable solution because the project is meant to be executed as an applet, and therefore must be totally contained within signed jars.
3- I was using an ApplicationContext before (ClassPathXmlApplicationContext to be exact), but the result was the same.
4- I'll try to find all three files using ClassPathResource instances before the BeanFactory initialization, to see how it goes.

I'll post new developments soon.
 
François Coupal
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, I got help from a fellow programmer and the problem was thus:

But first, an exerpt from the Spring documentation:

4.3.2. ClassPathResource

This class represents a resource which should be obtained from the classpath. This uses either the thread context class loader, a given class loader, or a given class for loading resources.

This Resource implementation supports resolution as java.io.File if the class path resource resides in the file system, but not for classpath resources which reside in a jar and have not been expanded (by the servlet engine, or whatever the environment is) to the filesystem. To address this the various Resource implementations always support resolution as a java.net.URL.

A ClassPathResource is created by Java code explicitly using the ClassPathResource constructor, but will often be created implicitly when you call an API method which takes a String argument which is meant to represent a path. For the latter case, a JavaBeans PropertyEditor will recognize the special prefix classpath:on the string path, and create a ClassPathResource in that case.



In a nutshell, this means that you must NOT use a normal File(String) constructor with a Spring resource, because the underlying implementation will try to use some kind of absolute path. Therefore, to prevent this, you must use the getFile() method from a URL object (as the documentation says in a weird way). That URL object can be fetched from the Resource instance. The resulting path will be the correct one.

That means that Paul's hunch was correct: the error was not in the Spring loading sequence (despite the stacktrace) but in the bean class setters. I was fooled, but to my defense it really was counter-intuitive.

I corrected the code and it works. See below.

Also, I corrected another error in the code: the ResourceLoaderAware interface only calls the SetResourceLoader() method in a context. Therefore, we must use an ApplicationContext instead of a bean factory in the main class for it to work. It will throw an NullPointerException otherwise because the init() method will be called without the resourceLoader being initialized.

Main class:


test class:


The other files have not been altered. (Edit: as a matter of fact, both file paths in the config.xml have been modified to the following form: "classpath:filename.txt")

My problem is solved. Thank you for your input.
reply
    Bookmark Topic Watch Topic
  • New Topic