I am running a tool (a virtual globe) through code from a jar file. The code reads a resource (an XML file) to provide some configuration options, using syntax like this, in a method of class Config:
URL localURL = Config.class.getResource("Config.xml");
I would like to provide my own Config.xml file with settings that override those in the file contained in the jar file.
I am not clear about how I can do this. I understand that the getResource() method explores the classpath to find the resource. So I thought of this:
- putting a copy of the file with my own settings in a specific directory
- putting this directory in front of the classpath
But to no avail: the getResource() still always loads the resource from the jar file.
I must be missing something ...
I tried removing the Config.xml file from the application jar. That fails: the application fails because getResource() returns null. It seems to me like
Config.class.getResource("Config.xml")
only looks for resources inside the jar file that contains class Config, whereas I thought it was looking in the classpath.
OK, got it. The issue is this: my Config class is really in a package, i.e. vis.globe.Config.java, so getResource("Config.Xxml") really looks for a file called vis.globe.Config.xml.
Therefore, with a classpath such as "../config:../jar/appl.jar", it will look for file Config.xml, not in ../config, but in ../config/vis/globe.
So the solution was to create a sub-directory structure in ../config that reflects the fully qualified name of class Config.java, i.e.
../config/vis/globe/Config.xml
You could always look to do something programmatically. So for example you would first search for a file named UserConfig.xml and if it was not found fall back on the file named Config.xml which would be found in the jar file.
Related
I'm trying to grab a resource in ClassLoader. A simplified version of the code looks something like this:
String ePath = "rewrite/common/RenameFunctor.groovy"
String fPath = ThClType.class.getClassLoader().getResource(ePath);
the response I get back as fPath is jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes!/rewrite/common/RenameFunctor.groovy. The actual path to the resource we want it exactly that, except without the second exclamation point. (Unlike warName.war, classes is just a normal directory.)
Does anyone know what might have caused the extra exclamation point and/or what might be done to fix it? This is as part of a process of updating some pretty old code that I didn't write, so if esoteric customization of ClassLoader behavior is possible, it's possible it's been done in this case. if it is possible, then I don't know how to check, and would appreciate any insight.
Warning: this answer is part supposition and guess-work on the mechanics, it may not be 100% correct, but I think it comes close enough. As far as I know actual WAR class loading will vary per servlet container or application server, so this answer may not hold for all of them.
If you look at
jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes!/rewrite/common/RenameFunctor.groovy
you can split it up in the following parts:
file:/Users/myName/warPath/warName.war
/WEB-INF/classes
/rewrite/common/RenameFunctor.groovy
The actual resource that is on the class path is the last one, /rewrite/common/RenameFunctor.groovy, the other parts are the coordinates used by the war class loader to find the part of the class path that contains that resource: first the location of the war file itself, file:/Users/myName/warPath/warName.war, and then the path within the war, /WEB-INF/classes.
This theory build on the documentation of the JarURLConnection which states:
A URL Connection to a Java ARchive (JAR) file or an entry in a JAR
file.
The syntax of a JAR URL is:
jar:<url>!/{entry}
for example:
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class
Jar URLs should be used to refer to a JAR file or entries in a JAR
file. The example above is a JAR URL which refers to a JAR entry. If
the entry name is omitted, the URL refers to the whole JAR file:
jar:http://www.foo.com/bar/baz.jar!/
So for a plain jar, the first part of the URL identifies the jar file itself, and the second part identifies the resource within the jar.
Technically war files are jar files, but contrary to jar files, the war file itself is not part of the class path. Instead it contains elements that are added to the class path., for example jar files in WEB-INF/lib and the classes and other files in WEB-INF/classes.
The ! separated parts then define the steps taken by the war class loader to locate a specific resource, in this case /rewrite/common/RenameFunctor.groovy.
I am trying to read a Properties file in a maven nature project using the Properties.load(); I am specifying a path as a string ex. "./someFolder/file.properties",
but when I try to use my project as dependency in other projects I am forced to copy those files to the other project , simply because the "." means current directory.
Is there a way to specify a path so it will always be valid despite where I am calling it from ? ,
I have tried using the MyClass.class.getClassLoader().getResourceAsStream() but I am having trouble using it , it worked sometimes and failed other times.
There are lots of misconceptions in your question.
"." means classPath
No. When used inside a filesystem path (i.e. a path passed to the constructor of a File, or FileReader, or FileInputStream), "." means the current directory.
When used in a resource path (i.e. passed to Class[Loader].getResource[AsStream]()), it's invalid.
The trick is to carefully read the documentation.
getResourceAsStream() expects a /-separated path.
When using ClassLoader.getResource[AsStream](), this path always starts from the root of the classpath. So you would pass a path looking exactly like a fully qualified class name, except the dots would be replaced by slashes. So, com/foo/bar.properties looks for a resource named bar.properties, in the package com.foo.
When using SomeClass.class.getResource[AsStream](), either the path starts with a /, and the path starts from the root of the classpath, or it doesn't, and it starts from the package of SomeClass. So, if SomeClass is in the package com.foo, using /com/foo/bar.properties is equivalent to using bar.properties.
It's hard to tell what you're doing wrong, since you're not providing any detail. But you really need to understand the difference between opening a file on the file system, and reading a resource loaded by the class loader. Sometimes, the resources just happen to be loaded by the class loader from the filesystem, because the classpath happens to contain directories, and not just jar files.
I noticed that my problem was that I had my properties files in the project path itself, and that the ClassLoader.getResource[AsStream](); looks is the target/classes folder, and that I didn't have the resources folder in my project.
I solved it my adding the resources folder to my build path and adding my files in the src/main/resources as the following src/main/resources/foo/bar.properties and loading it by SomeClass.class.getClassLoader().loadResourceAsStream("foo/bar.properties");.
So I have a GWT project and on the server side I am trying to load a properties file into a resource bundle, but am failing. I keep getting a missing resource exception because it can't locate the file but every option I've tried doesn't work. I've tried placing the config.properties file in war/config/config.properties as well as src/config/config.properties (so 2 copies) and I've tried calling it the following ways
TestGWTProject.war.config.config.properties
TestGWTProject.war.config.config
TestGWTProject.src.config.config.properties
TestGWTProject.war.config.config
src.config.config.properties
src.config.config
and my current call is this
ResourceBundle bundle = ResourceBundle.getBundle("config");
yet nothing works. Ideally, I'd like to keep it in the war file, but if it has to stay in src no biggie, but I'd like to just be able to find it at this point. What am i overlooking?
If you put your properties in the src folder (as I think you should) you need to give ResourceBundle a class-like qualified name, so that when application gets compiled, it can find the properties file in the classes folder.
In my case, for ex., I place them in my source folder, inside a package. Like this:
src/package/subpackage/subsubpackage/propertiesFile.properties
When I want to load the properties, I use this as the qualified name:
package.subpackage.subsubpackage.propertiesFile
This is the same way you would give your application a full qualified name for a class. The key here is that the properties file is getting copied to the classes folder inside the WAR. So your mistake was telling the ResourceBundle to look into the src folder.
This is the well known problem of loading resources from a jar file. This is not the first time I've tried to do this, but now it doesn't work the way I expect it to.
Normally I try to load the Resources with this.getClass.getResource("foo.png"), or getResourceAsStream()and it works. Now however it does not. The Resource is always null.
If I let System.out.println(this.getClass.getResource("")) print me the path (from eclipse) it shows /path/to/eclipseproject/package/structure/. Running this from a jar it just shows rsrc:package/structure
If I recall correctly this should print the path to the jar. Furthermore I thought this would print the package structure in both cases. Am I doing something wrong?
Here is the thing...
When Extracting the file from the Jar use:
this.getClass.getResource("/foo.png")
When running from a runnable Jar use, to reference an external file in the Jar folder path:
this.getClass.getResource("foo.png")
// When running this from Eclipse, it would refer to files in project root!
I have a code in the lower level determining where I'm running from to determine the correct path.
Doe this get the path you need?
this.getClass().getClassLoader().getResource("<your class name>.class").getPath();
See also this question for more on this issue.
Unless you prepend the path to the resources with '/', Class.getResource() will search for the resource in class package. E.g.: tld.domain.Foo.class.getResource("Bar.txt") will search for tld/domain/Bar.txt
Check the URLClassLoader for all the gory details, but it really depends on whether you are trying to access a ressource in the jar,
using a class loaded inside the same jar, in this case your file 'root' is the root of the jar
using a class loaded outside the jar (your eclipse case) where the root is your 'working directory'
To access resources inside a jar from outside, you should use something like
URL url = new URL( "jar", "", "file:" + jar.getCanonicalPath( ) + "!/" + localPathResource );
url.openStream(...)
This answer provides an explanation of how to load class resources from JAR files, even when the class is not in the JAR file and not in the Class-Path specified in the JAR file's manifest. There are also links to code.
Lots of confusion in this topic. Several Questions have been asked. Things still seem unclear.
ClassLoader, Absolute File Paths etc etc
Suppose I have a project directory structure as,
MyProject--
--dist
--lib
--src
--test
I have a resource say "txtfile.txt" in "lib/txt" directory. I want to access it in a system independent way. I need the absolute path of the project.
So I can code the path as abspath+"/lib/Dictionary/txtfile.txt"
Suppose I do this
java.io.File file = new java.io.File(""); //Dummy file
String abspath=file.getAbsolutePath();
I get the current working directory which is not necessarily project root.
Suppose I execute the final 'prj.jar' from the 'dist' folder which also contains "lib/txt/txtfile.txt" directory structure and resource,It should work here too. I should absolute path of dist folder.
Hope the problem is clear.
You should really be using getResource() or getResourceAsStream() using your class loader for this sort of thing. In particular, these methods use your ClassLoader to determine the search context for resources within your project.
Specify something like getClass().getResource("lib/txtfile.txt") in order to pick up the text file.
To clarify: instead of thinking about how to get the path of the resource you ought to be thinking about getting the resource -- in this case a file in a directory somewhere (possibly inside your JAR). It's not necessary to know some absolute path in this case, only some URL to get at the file, and the ClassLoader will return this URL for you. If you want to open a stream to the file you can do this directly without messing around with a URL using getResourceAsStream.
The resources you're trying to access through the ClassLoader need to be on the Class-Path (configured in the Manifest of your JAR file). This is critical! The ClassLoader uses the Class-Path to find the resources, so if you don't provide enough context in the Class-Path it won't be able to find anything. If you add . the ClassLoader should resolve anything inside or outside of the JAR depending on how you refer to the resource, though you can certainly be more specific.
Referring to the resource prefixed with a . will cause the ClassLoader to also look for files outside of the JAR, while not prefixing the resource path with a period will direct the ClassLoader to look only inside the JAR file.
That means if you have some file inside the JAR in a directory lib with name foo.txt and you want to get the resource then you'd run getResource("lib/foo.txt");
If the same resource were outside the JAR you'd run getResource("./lib/foo.txt");
First, make sure the lib directory is in your classpath. You can do this by adding the command line parameter in your startup script:
$JAVA_HOME/bin/java -classpath .:lib com.example.MyMainClass
save this as MyProject/start.sh or any os dependent script.
Then you can access the textfile.txt (as rightly mentioned by Mark) as:
// if you want this as a File
URL res = getClass().getClassLoader().getResource("text/textfile.txt");
File f = new File(res.getFile());
// As InputStream
InputStream in = getClass().getClassLoader()
.getResourceAsStream("text/textfile.txt");
#Mark is correct. That is by far the simplest and most robust approach.
However, if you really have to have a File, then your best bet is to try the following:
turn the contents of the System property "java.class.path" into a list of pathnames,
identify the JAR pathname in the list based on its filename,
figure out what "../.." is relative to the JAR pathname to give you the "project" directory, and
build your target path relative to the project directory.
Another alternative is to embed the project directory name in a wrapper script and set it as a system property using a -D option. It is also possible to have a wrapper script figure out its own absolute pathname; e.g. using whence.