adding relative directory to java classpath and using ClassLoader().getResourceAsStream("") - java

Is it possible to add a relative directory (ie, foo/bar/plugh) to the java classpath and use
InputStream in = getClassLoader().getResourceAsStream("xyzzy.properties");
To fetch foo/bar/plugh/xyzzy.properties?
My classpath looks like this:
foo.jar;foo/bar/plugh;xyz.jar
And I am able to use classes and resources from both foo and xyz jars but not from the plugh directory. In those cases, in is always null.
I can't get this to work and am not sure if this is just unsupported, I am missing something subtle or if I'm doing something wrong. Do I need to use an absolute path?

Maybe I'm misunderstanding what you're trying to do, but if you have a folder in your classpath, that means all the files underneath it should be in the classpath as well. If not, you can always pass each .properties file on the class path.
But either way, since the file/folder that contains the file is in the classpath, you should just be able to do:
InputStream in = new FileInputStream("classpath:xyz.properties")
And since "foo/bar/plugh" is in the classpath, one of the places it will look for xyz.properties is in "foo/bar/plugh".

Related

Reading xml file outside jar in java

I need to read an xml file which is outside the jar.I don't want to use relative path. It's an absolute path on unix box. As far as I understand, I guess there are 2 ways:-
1) Change the manifest file of jar and add that location in the classpath. In this case can I use getResource()?
2) Hardcode the path in getResourceAsStream(). My path is going to be something like this "/usr/local/folder1/folder2/".I read that I can't use getResource() for anything outside classpath and I need to use getResourceAsStream().
Which of these ways is a better approach?
Yes, both getResourceAsStream and getResource are dependent on the paths visible to the class loader that loads your class or the bootstrap class. If you want to use absolute paths, just use FileInputStream.
InputStream inputStream = new FileInputStream("/usr/local/folder1/folder2/myxml.xml");

how to find a local resource from dependent jar?

I have written a code that is packed to 1.jar
with this code:
return isProd? "/etc/waze/automation/devices.json":
DeviceRepositoryFromJsonFile.class.getClassLoader().getResource("devices.json").getPath().toString();
devices.json is here:
I have another project that depends on 1.jar
however the classLoader doesn't find the local devices.json file but rather one packed in the jar
anyhow it shows the file doesn't exist.
How can I fix this? just use a absolute path anyhow?
If as in your screenshot the devices.json locate in the src/main/resources and the package have successfully treat that as the package path and put in the jar file root directory, then you can just find the file via:
DeviceRepositoryFromJsonFile.class.getResource("/devices.json");
Note the "/" slash is important to indicate that to search from the root of the classpath.
It does not answer your question directly, but it may solve your problems faster.
As far as I can see you try to detect the absolute path to json file and pass it to another method so this file could be processed. Instead, it could be done simpler:
public byte[] getDevicesJsonBytes() {
return isProd
? IOUtils.toByteArray(ABSOLUTE_PATH_TO_PROD_FILE)
: IOUtils.toByteArray(DeviceRepositoryFromJsonFile.class.getResourceAsStream(RESOURCE_CLASSPATH);
}
The common way to read classpath resources it to use getResourceAsStream on class or classLoader instance. Also, many frameworks have their own resources abstractions, but I guess you don't need them now.

Resource loading in Java not working as it should

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.

Find conf file regardless how application started

I'm newbie to java.
I have some directory structure
product/
conf/
classes/com/../..
conf/ contains some configuration file, while under classes/ I have my application.
How can I ensure from inside java code that I'm able to find file in conf/ despite way I'm executing it (e.g. from eclipse, from different directories, from crontab etc.).
P.S.
Files in conf/ are not resources, since required to be edited by user.
Is there're way to know where my .class, so I canuse relative path form that directory to reach my directory (e.g. MY_CLASS_DIR/../../../../conf)
I would put the conf directory into the class path. That way you can always find them by:
YourClass.class.getClassLoader().getResource("conf/....");
You can use the absolute path, including the way to product.
Or you may use a configuration setting, by starting your program like
java -DXY_HOME=/some/path/product ...
From the javacode, you use it:
String xyHome = System.getProperty ("XY_HOME")
Or you use a kind of inifile in your home directory, where you specify where to look for the conf-directory.
Rereading your question multiple times, it is unclear to me what your goal is. To find the conf dir independently from where you are (eclipse, crontab, ...)? But the headline asks for the CWD, which is the opposite - the directory, depending on where you are.
Both is possible, but you have to decide what you want.
Its safe to use relative paths than absolute paths. Even if you JAR your classes tomorrow it will work as is,
Put you configuration files in classpath during deployment.(Please note that
project directory structure can be different from that of deployment directory structure)
product/
classes/com/../..
classes/conf/some_conf.properties
Then you can use Apache common configuration to get the URL of file
URL urlOfFile = org.apache.commons.configuration.
ConfigurationUtils.locate("conf/some_conf.properties");
The other alternative you can try is,
URL urlOfFile = <SomeClassFromClassesFolder>.class.
getClassLoader().getResource(resourceFile);
Once you get the URL of your configuration file getting stream out of it very simple,
InputStream stream = urlOfFile.openStream();
Good luck.
For you understanding you can refer the following as well,
http://bethecoder.com/applications/tutorials/showTutorials.action?tutorialId=Java_IO_CurrentWorkingDirectory
http://bethecoder.com/applications/tutorials/showTutorials.action?tutorialId=Java_Reflection_WheretheClassloadedfrom
Good luck.
you can find out what is the absolute path of the working dir by:
String str = new File("").getAbsolutePath()

Absolute Path of Project's folder in Java

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.

Categories