Path for retrieving resources with ClassLoader - java

Basically, I want to include my main JFrame's icon in the JAR file, so not to need to load it from an external location.
To achieve this, I searched about Java's resource system.
What I have done with Eclipse:
I have created a new folder named "res":
I have copied the files inside it using Windows' explorer:
I have made that folder a source folder:
I have written this code:
URL url = ClassLoader.getSystemResource("/res/icona20.ico");
But url is null.
What did I do wrong?

As mentioned you seem to have added res as source folder, so it is a root, not to name, like src.
URL url = ClassLoader.getSystemResource("icona20.ico");
Class loaders use an absolute (case-sensitive) path, without explicit leading slash /....
Relative paths with an obligatory leading slash for absolute paths:
URL url = Xyz.class.getResource("/icona20.ico");
And you might prefer .png instead of .ico as the latter format is not standard in Java SE.
(About common practices.) The build tool maven uses as nice standard the following source folders:
/src/main/java/
/src/main/resources/
/src/test/java/
/src/test/resources/
Your usage of res is reminiscent of MS Visual Studio ;).

The classloader will get the resources starting from each source folder you added to the classpath. Therefore, the URL should be the following:
URL url = ClassLoader.getSystemResource("icona20.ico");

Related

Java: getResource image, cannot be found.

I just came up with an error in Java (using Eclipse). I want to load an image from the resource folder into the application. Using the follwoing lines:
URL url = this.getClass().getClassLoader().getResource("/resources/images/icon.png");
BufferedImage i = ImageIO.read(url);
But this results in a java.lang.IllegalArgumentException: input == null! exception.
My folder structure is:
How can I access this image? Thank you a lot!
getResource() returns null if it can't find the resource on the classpath.
In order to use getResource() you need the resources to be on the classpath. The resources directory isn't on the classpath. In Eclipse, you could add the resources folder to the classpath. Or create a new package images under srcServer and move the icon out of resources and into srcServer\images along with your source code.
Another way would be to load the image using a File rather than loading it as a classpath resource.
I believe the reason why it doesn't find the resource is due to your syntax. getClass().getClassLoader().getResource() takes the input without the leading '/' and always starts at the root of the classpath. getClassLoader().getResource() is always an absolute path, whereas getClass().getResource() is a relative path.
Just use:
URL url = this.getClass().getResource("/images/icon.png");

Java: Access relative path outside ANY module

I have a java project that consists of several modules:
myWebApp
- conf //not a java module, just text files
- ModuleA
-- src
-- target
-- moduleA.iml
-- pom.xml
- ModuleB
...
- pom.xml
- myWebApp.iml
- myWebApp.env
I want to access myWebApp.env file (which is a java properties file) from a Class (which is obviously under a module's src folder), like:
InputStream is = new FileInputStream(<RelativePathToEnvFile>);
The problem is that relative paths seem to work only for subdirectories under modules' source root, or anywhere inside the classpath using the getResource() trick as mentioned here
On every other language I know I could do something like:
InputStream is = new FileInputStream("../../../../../myWebApp.env");
Isn't this possible in java?
Since Java 7 you could do this with NIO Files API (old File API would work as well, but relative path resolution is done nicer with NIO)
File file = Paths.get("../../pom.xml").toFile();
To ensure, the file is correct, you could invoke toRealPath() to resolve the relative path segments
File file = Paths.get("../../pom.xml").toRealPath().toFile();
In case you have a working dir to start from, you could resolve a relative path from that:
File file = Paths.get(".") //the current working dir
.resolve("../pom.xml") //navigate to a relative path
.toFile(); //convert to old File api
When working with an IDE, you have to ensure, the working dir is correct. It is not necessarily the case that the working dir is the same module dir as the executed class belongs to. The working dir could be that of the project/parent module.
In addition, your code may only work in that particular setup. At least you should consider putting the env file in the resources folder of one of your modules (or have a separate config module) and then resolve the file in the classpath.

Java: getCodeBase() on non-applet application

I'm trying to create a URL to access a local file like so:
URL myURL = new URL(getCodeBase(), "somefile.txt");
But it throws a NullPointerException when it attempts getCodeBase(). I'm fairly certain that the reason behind this is because the class file that this code belongs to is not an applet. Is there any way I can get the code base without using an applet? I just want to access a local file without having to put the actual directory in (because when others run the application the directory path will obviously not be the same).
I would use the following to be relative to the working directory
URL myURL = new URL("file:somefile.txt");
or
URL myURL = new URL("file", "", "somefile.txt");
or
File file = new File("somefile.txt");
You don't need to get the code base.
If the file resides on your classpath (this includes the path where your classes are deployed), you can access vía the ClassLoader method getSystemResource.
URL myURL = ClassLoader.getSystemResource("somefile.txt");
If somefile.txt is read-only, put it in a Jar that is on the run-time class-path of the application. Access it using:
URL urlToText = this.getClass().getResource("/path/to/somefile.txt");
If it is read/write:
Check a known sub-directory of user.home for the file.
If not there, put it there (extracting it from a Jar).
Read/write to the file with known path.
See How to create a folder in Java posting, which asked very similar question.
As Tomas Narros said above, the proper way to do this is to use the ClassLoader to locate resource files in the Classpath. The path you pass to the ClassLoader is relative to the classpath that was set when you started the Java app.
If you browse the above link, you'll see some sample code showing how to resolve the path to a file in your classpath.

Java (maven web app), getting full file path for file in resources folder?

I'm working with a project that is setup using the standard Maven directory structure so I have a folder called "resources" and within this I have made a folder called "fonts" and then put a file in it. I need to pass in the full String file path (of a file that is located, within my project structure, at resources/fonts/somefont.ttf) to an object I am using, from a 3rd party library, as below, I have searched on this for a while but have become a bit confused as to the proper way to do this. I have tried as below but it isn't able to find it. I looked at using ResourceBundle but that seemed to involve making an actual File object when I just need the path to pass into a method like the one below (don't have the actual method call in front of me so just giving an example from my memory):
FontFactory.somemethod("resources/fonts/somefont.ttf");
I had thought there was a way, with a project with standard Maven directory structure to get a file from the resource folder without having to use the full relative path from the class / package. Any advice on this is greatly appreciated.
I don't want to use a hard-coded path since different developers who work on the project have different setups and I want to include this as part of the project so that they get it directly when they checkout the project source.
This is for a web application (Struts 1.3 app) and when I look into the exploded WAR file (which I am running the project off of through Tomcat), the file is at:
<Exploded war dir>/resources/fonts/somefont.ttf
Code:
import java.io.File;
import org.springframework.core.io.*;
public String getFontFilePath(String classpathRelativePath) {
Resource rsrc = new ClassPathResource(classpathRelativePath);
return rsrc.getFile().getAbsolutePath();
}
In your case, classpathRelativePath would be something like "/resources/fonts/somefont.ttf".
You can use the below mentioned to get the path of the file:
String fileName = "/filename.extension"; //use forward slash to recognize your file
String path = this.getClass().getResource(fileName).toString();
use/pass the path to your methods.
If your resources directory is in the root of your war, that means resources/fonts/somefont.ttf would be a "virtual path" where that file is available. You can get the "real path"--the absolute file system path--from the ServletContext. Note (in the docs) that this only works if the WAR is exploded. If your container runs the app from the war file without expanding it, this method won't work.
You can look up the answer to the question on similar lines which I had
Loading XML Files during Maven Test run
The answer given by BobG should work. Though you need to keep in mind that path for the resource file is relative to path of the current class. Both resources and java source files are in classpath

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