Relative path for library exporting in Java - java

I'm trying to export a .JAR to be used as library to other projects. The problem is that I need to use relative paths when referencing files inside this library, but the only solutions I found were using absolute paths like:
private static final String FILE = new File("").getAbsolutePath().concat("/src/bla/file.txt");
Obviously whenever I try to run this line of code as an exported library I'll get something like DRIVE/project/src/bla/file.txt which is not correct since this .JAR can be anywhere inside DRIVE/projects like DRIVE/projects/lib/myLib.jar.
In Nodejs we had easy functions to retrieve relative paths according to the runtime location. How can I reference files in such a way that it will capture the "runtime path" so that I can safely reference them and the path will be dynamically solved?
For those who are so eager to mark this question as duplicate, please read with attention first. I'm NOT asking how to READ files from resources!

To use the "file.txt" present in the classpath,we need to make sure the "file.txt" is present in the directory represented by classpath.
Assume you have all the class files generated in a directory named "/home/abcuser/target".
For simplicity we will place the file.txt in the target directory root level.
The main class is say TestFileAccess.class(the class with the main method)
To execute the main class present in the target directory you can use the below command
java -cp /home/abcuser/target TestFileAccess
Now, the classpath in this case is /home/abcuser/target
To access the resources on classpath,you can go with two ways.
ClassLoader.getSystemResource and ClassLoader.getSystemResourceAsStream methods.
Class.getResource and Class.getResourceAsStream
The main difference between the ClassLoader and Class versions of the methods is in the way that relative paths are interpreted.
The Class methods resolve a relative path in the "directory" that corresponds to the classes package.
The ClassLoader methods treat relative paths as if they were absolute; i.e. the resolve them in the "root directory" of the classpath
Using ClassLoader you can use the below snippet
InputStream inputStream = ClassLoader.getSystemResourceAsStream("file.txt");
To explicitly reference a resource as a classpath file you can add the resource path to the classpath while executing the java code.
Let's say your resource "file.txt" is in /home/abcuser/resources.
You can add the the resource path to the classpath during the java execution start as shown below
java -cp "/home/abcuser/target:/home/abcuser/resources" TestFileAccess

Related

Can't enumerate `class` files with ClassLoader#getResources()

I am trying to enumerate classes in the package with
Enumeration<URL> resourceUrls = myObject.getClassLoader().getResources("path/to/my/package/");
while (resourceUrls.hasMoreElements()) {
...
Unfortunately it returns nothing. Why?
Assuming path is correct. Path starts with no slash and ends with slash. There are several public classes under path.to.my.package package.
I took this code from Spring.
You cannot walk a class path like you can walk a file path. Walking a file path is done on the file system, which does not apply to a class path.
While a java class path entries are formed like file paths and usually are folders and files (either on the file system or inside a JAR archive), it does not necessarily have to be that way. In fact, the classes of one single package may originate from various locations of differing nature: one might be loaded from a local JAR file while another one might be loaded from a remote URL.
The method ClassLoader.getResources() exists to provide access to all "occurrences" of a resource if it has the same name in different JAR files (or other locations). For example you can use
ClassLoader.getSystemClassLoader().getResources("META-INF/MANIFEST.MF");
to access the manifest file of each JAR file in your class path.
Try with
Enumeration<URL> urls = ClassLoader.getSystemClassLoader().getResources("path/to/my/package");
while (urls.hasMoreElements()) {
System.out.println(urls.nextElement());
}

Using relative path in a maven project

I have a maven project with these standard directory structures:
src/main/java
src/main/java/pdf/Pdf.java
src/test/resources
src/test/resources/files/x.pdf
In my Pdf.java,
File file = new File("../../../test/resources/files/x.pdf");
Why does it report "No such file or dirctory"? The relative path should work. Right?
Relative paths work relative to the current working directory. Maven does not set it, so it is inherited from whatever value it had in the Java process your code is executing in.
The only reliable way is to figure it out in your own code. Depending on how you do things, there are several ways to do so. See How to get the real path of Java application at runtime? for suggestions. You are most likely looking at this.getClass().getProtectionDomain().getCodeSource().getLocation() and then you know where the class file is and can navigate relative to that.
Why does it report "No such file or dirctory"? The relative path should work. Right?
wrong.
Your classes are compiled to $PROJECT_ROOT/target/classes
and your resources are copied to the same folder keeping their relative paths below src/main/resources.
The file will be located relative to the classpath of which the root is $PROJECT_ROOT/target/classes. Therefore you have to write in your Pdf.java:
File file = new File("/files/x.pdf");
Your relative path will be evaluated from the projects current working directory which is $PROJECT_ROOT (AFAIR).
But it does not matter because you want that to work in your final application and not only in your build environment. Therefore you should access the file with getClass().getResource("/path/to/file/within/classpath") which searches the file in the class path of which the root is $PROJECT_ROOT/target/classes.
No the way you are referencing the files is according to your file system. Java knows about the classpath not the file system if you want to reference something like that you have to use the fully qualified name of the file.
Also I do not know if File constructor works with the classpath since it's an abstraction to manage the file system it will depend where the application is run from. Say it is run from the target directory at the same level as source in that case you have to go one directory up and then on src then test the resources the files and finally in x.pdf.
Since you are using a resources folder I think you want the file to be on the classpath and then you can load a resource with:
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("<path in classpath>");
Then you can create a FileInputStream or something to wrap around the file. Otherwise use the fully qualiefied name and put it somewere like /home/{user}/files/x.pdf.

Reading file form classpath

I have a maven project and want to read file in it form its class path. The code that i am using is
InputStream is = getClass().getResourceAsStream ("filename.json");
But every time i am getting null inputstreams. I am not sure why ?
The file is places under /src/main/resources. The same folder which contains log4j.xml and it is being picked up decently.
Please note, I am trying to run this file from Eclipse i.e., run or debug mode. No vm arguments or whatsoever.
The Class.getResourceAsStream(String) method looks for the given resource within the same namespace (i.e. package) that the given class is in unless you give it an absolute path (see the API documentation); If it can't find the resource on the classpath in this namespace, it returns null. Since your class is likely inside e.g. com.myproject.resourcemanagement, your resource file has to analogously be under src/main/resources/com/myproject/resourcemanagement, similary to how your class source files are organised (under src/main/java/com/myproject/resourcemanagement).

Why does the Java compiler say my file was not found in the class path when I can clearly see it in the class path?

I am using java -classpath $CLASSPATH ..., where $CLASSPATH has been set to /file1path/file1:/file2path/file2 and so on. Despite this, Java complains that file1 is not found. I tried to set -Dfile1=file:///fullpath/file1, but it still says it cannot find the file. Is there any reason why this might happen other than that I am not seeing a simpler problem like a typo or something (which I have checked for many times)?
More specifically, this.getClass().getClassLoader().getResourceAsStream(configurationFileName) is returning null.
The file that is not being found is a configuration file (.properties), not a JAR file.
You set a classpath to point to a directory containing something or an archive containing resources. I don't believe you can add a resource directly to the classpath.
Try setting your classpath to /file1path instead of /file1path/file1
The classpath should specify the directory where your package hierarchy rooted.
package org.djna, file system : C:/myhome/javastuff/org/djna/Myclass.java
classpath is set to c:/myhome/javastuff
If you are trying to open files from your application using getResourceAsStream() or some such the the details of the path depend on whether or not the filename has a leading /. Read the docs caefully and all will become clear.

How to resolve path of a static file in Java?

How can I find path of a xml (static myXml.xml) file that is embedded into jar? Obviously not by absolute path but I am facing same kind of problem with relative paths. I cannot get it relative to home folder as Java returns different home folder depending upon from where I am calling the accessing Java class. For instance, from:
command prompt
App server
Eclipse launcher
Eclipse remote debugger etc
Is there someway that my accessing class (packed in same jar) may access embedded xml regardless of where jar file exists and who is trying to access it?
What you need to do is use the class loader to load the file:
InputStream stream = this.getClass().getClassLoader().
getResourceAsStream("myXml.xml");
The above code assumes that the file is at the top level of your jar.
Have you tried the getResource and getResourceAsStream methods in the Class class? Usually those are what I have to resort to in these situations.
Hope this helps.
You can use ClassLoader#getResource(..) to get InputStream of a file from the classpath:
Object.class.getClassLoader().getResource().openStream()
Also there are some other methods in ClassLoader which could be useful in your case.

Categories

Resources