Java: Loading resources from the file system - java

My Project Setup
I have the following project setup:
\program.jar
\images\logo.png
In my code, I reference the image with the relative URL "images/logo.png".
Problem
If I run this program with the following command while in the directory:
c:\projects\program_dir\bin\>java -jar program.jar
Then everything works and Java is able to locate the image.
Now, my problem is, that I need to be able to run the program from a different directory.
c:\>java -jar c:\projects\program_dir\bin\program.jar
The program is executed, but now all the relative URLs no longer work.
What I need
How do I calculate the execution home of the program.jar file, so that I can change my relative URLs into absolute URLs?

What I would do, if possible, is package your images in with your Jar.
That way you don't have to worry about where your Jar is launched from.
You would then need to load images similar to the following:
InputStream stream = this.getClass().getClassLoader().
getResourceAsStream("/images/logo.png");

You should really include your resources in your JAR.
Failing that, you can parse the absolute path out of the Main class resource. Assuming your Main class is actually called "Main":
Main.class.getResource("Main.class").getPath();

Resources have to be in the class path(s). You may try one of these:
Placing the images into the program.jar.
Like most of the programs, they have a APP_HOME directory, e.g. MAVEN_HOME, register that and refer to your files as File instead - $APP_HOME/the-file.ext (with System.getenv()).

As Nelson mentioned, package them with your JAR (just copy them alongside your .class files), then you can find them via a simple this.getClass().getClassLoder().getResource("images/foo.png").

You need to add a parameter which describes your class path. Should look something like
java -cp c:\projects\program_dir\bin -jar program.jar
this will put your jar and image on the class path and it will load successfully.

Related

Executing a Java class file using the command line, but from the "wrong" directory

App.java is a simple "Hello World" app in directory /home/abcd and is part of package abcd; that is, it has a header package abcd;. I can easily compile and run the app, from the /home directory with javac abcd/App.java and run it from the upper (i.e. /home) directory with java abcd.App.
How can I run the class file from the "wrong" directory, e.g., from sub-directory abcd itself, or indeed from any other directory.
Despite having turned up several stackoverflow questions with titles that suggest they address this problem, none that I've found quite does so.
You need to specify /home as the class path (or rather, add it to the class path). It's the directory under which your package structure is located.
From anywhere, you can run
java -cp /home/ abcd.App
You can also use a relative path for the class path, which means this should work from within /home/abcd/:
java -cp .. abcd.App

How to add path to resource directory to an executable jar

I am trying to create an executable jar (code.jar) that depends on another jar file (other.jar) that I create in a separate project(=directory).
The problem I'm having is that there is a class in other.jar that looks for an image file (xyz.gif) that is contained within that project:
e.g., project 'other' looks like: build/ images/xyz.gif src/... etc.
I make other.jar (including the /images directory) and then I make code.jar.
However, when I run
java -jar code.jar - it is unable to locate xyz.gif:
java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(ImageIO.java...)
I have tried everything I can think of to communicate the path to images/xyz.gif to the jar, including:
1. I tried adding the CLASS-PATH: images/ to the MANIFEST.MF for other.jar
2. I tried copying the images directory into the build for code.jar and adding CLASS-PATH: images/ to the MANIFEST.MF for code.jar
3. I tried putting CLASS-PATH: images/xyz.gif - in both manifest files
This seems like a general problem: How to include a (non-class) resource (e.g., an image file) to a java jar file in
such a way that java can locate it (without subsequent packages that utilize the sub-package - e.g., code.jar uses other.jar)
needing to know the details.
Say I can successfullly run the code project using:
java -cp somepath/images com.xyz.code
What I want to do is run:
java -jar code.jar - and have it locate the images/ directory on the classpath.
I should add that the image-containing jar (other.jar) project is not my code - I am just trying to compile it to use. That code tries to load the image using:
javax.imageio.ImageIO.read(ClassLoader.getSystemResource("xyz.gif");
There seems to be a lot of discussion about whether this is the correct/best way to load an image - I assume that the authors of this code DID have it working using Eclipse (whi
ch likely sorted out the paths), and I simply want to get it working on the command line (and eventually in ant).
Any help would be greatly appreciated. I don't understand why the documentation on jar creation is so minimal.
Instead of running jar directly try putting it in classpath. Something like this:
java -cp code.jar MainClass
This might work.
EDIT:
Above solution will not work. Try the below code to get image.
ImageIcon myIcon = new ImageIcon( this.getClass().getResource("/resources/icon.gif"));
and place the image at below locations:
/myApp/src/resources/icon.gif
/myApp/bin/resources/icon.gif

How to get location of runnable .jar File when run from GNOME

I am developing a small Java application using Swing, that is supposed to run on Windows/Linux and MacOS.
Eventually it will ship as a runnable jar with some config files in the same folder. To load them I need the path to the folder the jar is stored in within the program.
There are already a couple of threads like this one or this one.
My problem is, that all the solutions discussed there work fine, when I run the program from within eclipse or call the runnable jar from a terminal like so:
java -jar /path/to/jar/jarfile.jar
However when I click on the jar file in Cinnamon or Gnome (which is what most of the users will know to do), I do not get the correct paths. (MacOS users report the same issue)
Here is what I've tried so far and what the output is when run via double click (all those display the desired path when run from eclipse or a terminal):
ClassLoader.getSystemClassLoader().getResource(".").getPath()
Output: file:/usr/lib/jvm/java-6-openjdk-common/jre/lib/ext/pulse-java.jar!/
SomeClass.class.getProtectionDomain().getCodeSource().getLocation().getPath();
Output: ./
System.getProperty("user.dir");
Output: /home/myusername
Is there any other way to do it or am I doing something wrong when exporting the jar? Any help would be appreciated!
Cheers
Nick
Make it simple, and use a startup script (.bat/.sh file) to run your application. This startup script will get the path of its own location in the filesystem, and pass it as an argument or system property to the Java application. This has the additional advantage of being able to pass other arguments, like the size of the heap, etc.
On windows, %~dp0 is the path of the directory containing the executed bat file. On Unix, you can use $(dirname $0).
You could store all config files as resources in a jar, and copy them to files in home.dir + ".AppName/".
Painful as it is, the Preferences API, Preferences.systemNodeForPackage, seems the wisest alternative, if there is little structured config data. There is an inputStream method for import; your initial config template could be a resource in the jar.
Just get the class path using System.getProperty("java.class.path") and scan it for your ".jar" name. Note that path separators are OS dependent (File.pathSeparator)

Java file access

At the moment, in my java program, I am accessing a file that is in the project folder. When I'm loading the file its path is "./src/package/package/file.txt". When I build the program into an executable it dosen't work.
I would prefer the files to be outside of the .jar, but in the same folder, how would I got about this?
Samishal
You can use a relative path if they are in the same folder, such as ./file.txt. That should carry over even with a compiled JAR.
Otherwise, if you're going to be using the same machine and are confident of the placement of the files, you could use an absolute path, however I don't recommend it.
You can use Class.getResourceAsStream to get the InputStream. It works for jar package too. It is not possible to access the file in jar file using File API directly.
InputStream ins = Class.getResourceAsStream("/gigadot/exp/resource.properties");
More details at http://blog.gigadot.net/2010/10/loading-classpath-resources.html
Because the relative path is relative to where your command prompt is when you execute the program, not from where the program lives.
You somehow need to tell the program where to find resources. Most people use a .sh/.bat script to figure out where the script itself lives, and either pass -D flags or set the classpath based on that location.
as a note, I $0 gives you the script as it was run on the command line in linux (it could be relative or absolute), and you can use dirname from there to find it's directory, and alter the java command line.
in windows %~dp0 gives you the directory of the batch script which was run, and you can use that to form your java command line.

Java Command Line Program Classpath Problem

so I have a pretty large project in Eclipse which runs fine and accesses files etc. And when in Eclipse I access files with a local directory name in relation to the root of the project directory.
So my project is called "Project1" for example and is inside a directory called "MyProjects" so it looks like this: "MyProjects/Project1". I want to access a file in the "MyProjects" folder called "hello.text". So I just do "../hello.text" and it works fine when I do this in Eclipse.
The problem I have is when I run the program using the command using "java Project1" it runs the program fine but it cannot access that file because when executing programs from the command line it stars them from the "bin" directory which is inside of the "Project1" directory. So it messes up the whole program. Is there anyway to change this easily in my Windows environment or Eclise? I hope my question makes sense. I want the program to execute from "Project1" directory if possible so I don't have to change the file location everytime.
You can use one of ClassLoader class methods
public URL getResource(String name)
or
public InputStream getResourceAsStream(String name)
to locate and access any resource in the classpath in a way that is independent of the location of the code. For exaple
InputStream myTextFileStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Project1/Hello.txt") ;
How about providing a directory argument so you don't have to worry about it at all ever?
Can't you start your Java program from the bin directory's parent?
e.g.
Project1> java -classpath bin MyApp
Does this answer for getting classpath from Eclipse help?

Categories