Relative paths to getResourceAsStream method - java

I have a jav aproject which is build through ant. It write the class files to output/classes/com/... path. One of my java classes needs input stream read from a file that is in a folder one level above output folder. Looks like if copy the file to the package folder under outptu/classes, it seems to work. But I do not want to palce my config file in output folder as it will be cleaned when I do ant clean. I want it to find it look above the output folder, in config folder and load it.
public static final String CONFIG_FILE="/../../../../../../../Config.txt";
public static ConfigObj getConfigObj() throws IOException {
InputStream i=ConfigLoader.class.getResourceAsStream(CONFIG_FILE);
...
I want to know when I want to give raltivepath, what should it be relative to. I tried looking up , it says relative to classloader. What is classloader in this case? Is it output/classes/com....../config folder where my ConfigLoader.class lives?

The problem is that getResourceAsStream() will only load resources from the classpath. I guess you only have output/classes on your classpath, so you will never be able to load the config file via getResourceAsStream() if it's outside that directory. Use a File with an absolut path pointing to the file, or place it in your classpath.

Related

File not found from resources folder

I have a file in my src/main/resources folder, the location of which i am passing in library function, but the file is not being read.
here is how the folder structure looks on decompiling the war
.
I have a file in my src/main/resources folder(Intuit.cto.gateway.aws.preprod.jks), the location of which i am passing in library function, but the file is not being read.
here is how the folder structure looks on decompiling the war.
when i create a simple maven project and try to do the same, i am able to access the file from src/main/resources
when i decompile my sample project it looks like this
To access the file, i am using this code :
public static void main(String args[])throws Exception{
FileReader fr=new FileReader("src/main/resources/filename");
int i;
while((i=fr.read())!=-1)
System.out.print((char)i);
fr.close();
}
how to solve this problem ?
You can't do it the way you want to.
Your path is most likely incorrect. Unzip your *.war file and see that src/main is no more.
If the war file is not exploded, you can't access its content by using simply path passed to a File* class, because your file is packaged as in zipped into standard location in a ZIP file with file extension WAR.
If your destination requires File or path which is passed to FileReader you have to read this file out of WAR file (using ClassLoader.getResourceAsStream()) and copying it out to a temporary location like File.createTempFile() or System.getProperty("java.io.tmpdir").
A resource (on the class path) is not necessarily a file system file. If the usage cannot deal with just an InputStream, one needs to create a temp file.
Path tempFile = Files.createTempFile("phoneid-", ".jks");
InputStream res = getClass().getResourceAsStream("/Intuit/gateway/preProd.jks");
// Case-sensitive, absolute path on the class path.
Files.copy(res, tempFile);
// Maybe:
//tempFile.toFile().deleteOnExit();
String param = tempFile.toString();
(A result null for getResource/getResourceAsStream indicates a wrong path.)
A partial solution would also be to check the URL of the resource, whether has the "file:" protocol, and not "jar:file:" (packed in a zip format, like jar, ear or war).
URL url getClass().getResource("/Intuit/gateway/preProd.jks");
With a class, the path can either be relative to the class package directory, or absolute ("/..."). If using the ClassLoader instead the path is always absolute, and should be written without / in front.

Java classloader not able to find resource in jar file

I have a runnable jar file which is not able to access my resources which reside outside of the default src directory. Based on my understanding from What is the difference between Class.getResource() and ClassLoader.getResource(), I should be able to access root/res/img/img1.png (see folder setup below) by using the following getResourceFile function:
public class Foo {
private static final ClassLoader CLASS_LOADER = Foo.class.getClassLoader();
public static File getResourceFile(String relativePath) {
// Since I'm using getClassLoader, the path will resolve starting from
// the root of the classpath and it'll take an absolute resource name
// usage: getResourceFile("img/img1.png")
// result: Exception in thread "main" java.lang.NullPointerException
return new File(CLASS_LOADER.getResource(relativePath).getFile());
}
}
folder setup:
root/
src/
foo/
bar/
res/
img/
img1.png
audio/
audio1.wav
The problem arises when I try to execute the jar executable itself. However, the strange thing is that I was not able to replicate this through eclipse IDE which was actually able to resolve the path correctly. I have added the resource directory to the build path via (Project -> Properties -> Java Build Path -> Add Folder) so Java should be able to find the resource folder at runtime.
Is there something I'm missing in terms of generating the jar file? When unpacking the jar file everything seems to be in order with the img and audio directories being in the root (given the above initial folder setup):
foo/
/bar
img/
img1.png
audio/
audio1.wav
Files can only be used to represent actual files in your filesystem. And once you package your files into a JAR, the resource (img/img1.png) is not a file anymore, but an entry in the JAR file. As long as you use the folder structure from within Eclipse, the resources are individual files so everything is fine.
Try this:
System.out.println(CLASS_LOADER.getResource(relativePath));
It will print a URL, but it will not be a valid path to a file in your file system, but to an entry within the JAR file.
Usually, you will only want to read a resource. In that case, use getResourceAsStream() to open an InputStream.

getResource will always return null

This is driving me crazy. I have a simple eclipse project with a src folder and a class in it. But I can't seem to get getResource to find it. What am I doing wrong?
import java.net.URL;
public class ContextTest {
public static void main(String[] args) {
URL url = ContextTest.class.getResource("/src/ContextTest.java");
System.out.println(url);
}
}
If I right-click on the class name, the path is /TestsProject/src/ContextTest.java and the default classpath according to the Classpath tab in Run Configurations is TestProject.
It doesn't work with /bin/ContextTest.java , /ContextTest.java , ContextTest.java either.
When you load resources using ContextTest.class.getResource("/....") the leading / is translated as an absolute path. Here absolute means from your root package (i.e. the default package).
In Eclipse the root package is considered the one that is under the src folder. Your compiled classes will be placed under bin folder and if you create a jar you will see that your root package is not the src or bin folders but whatever folders are inside it. (for example com).
So the correct way to load a resource using a class absolute path would be ContextTest.class.getResource("/ContextTest.java");. If the file ContextTest.java is in the root package of wherever your compiled classes are, then it will be found and returned.
I hope this clears the picture.
Update: From the comments below it is not clear what you are trying to do. When you use getResource() you are not loading a file but a resource from the classpath. This would correctly find the resource even if your files were inside a jar file. So for your above example to work the file you are trying to load as a resource should be in the classpath (i.e. under bin folder since this is the root of your classpath when you execute from inside Eclipse). If you are trying to load a file outside of your classpath then don't try to load a resource, you could use File instead.
Resources accessed via getResource() must be on the classpath. Your Java files will be compiled and placed on the classpath. The compiled .java file will be given an extension of .class.
Try
URL url = ContextTest.class.getResource("ContextTest.class");

How do I reference a resource in Java?

I need to read a file in my code. It physically resides here:
C:\eclipseWorkspace\ProjectA\src\com\company\somePackage\MyFile.txt
I've put it in a source package so that when I create a runnable jar file (Export->Runnable JAR file) it gets included in the jar. Originally I had it in the project root (and also tried a normal sub folder), but the export wasn't including it in the jar.
If in my code I do:
File myFile = new File("com\\company\\somePackage\\MyFile.txt");
the jar file correctly locates the file, but running locally (Run As->Java Main application) throws a file not found exception because it expects it to be:
File myFile = new File("src\\com\\company\\somePackage\\MyFile.txt");
But this fails in my jar file. So my question is, how do I make this concept work for both running locally and in my jar file?
Use ClassLoader.getResourceAsStream or Class.getResourceAsStream. The main difference between the two is that the ClassLoader version always uses an "absolute" path (within the jar file or whatever) whereas the Class version is relative to the class itself, unless you prefix the path with /.
So if you have a class com.company.somePackage.SomeClass and com.company.other.AnyClass (within the same classloader as the resource) you could use:
SomeClass.class.getResourceAsStream("MyFile.txt")
or
AnyClass.class.getClassLoader()
.getResourceAsStream("com/company/somePackage/MyFile.txt");
or
AnyClass.class.getResourceAsStream("/com/company/somePackage/MyFile.txt");
If I have placed i file in a jar file, it only worked if and only if I used
...getResourceAsStream("com/company/somePackage/MyFile.txt")
If I used a File object it never worked. I got also the FileNotFound exception. Now, I stay with the InputStream object.

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