I've made an audio player and the jar was made with netbeans. To load the images I've used:
ClassLoader cl = this.getClass().getClassLoader();
URL playerIconURL = cl.getResource("tp/audioplayer/Images/icon.png");
if (playerIconURL != null){
ImageIcon playerIcon = new ImageIcon(playerIconURL);
frame.setIconImage(playerIcon.getImage());
}
else{
System.err.println("cannot load player icon");
}
I mention that the folder Images is in the src/tp/audioplayer.
When I'm running the application inside netbeans everything is allright, but when I execute the jar in command prompt,the application starts but it's blank and it blocks and I get:
Can you tell me what I've done wrong or what is the problem? Thanks in advance!
If tp is in your classpath you will have to load it with cl.getResource("/tp/audioplayer/Images/icon.png") if tp is NOT a source folder (but still added to the buildpath.
If you add tp as a sourcefolder then
cl.getResource("/audioplayer/Images/icon.png")
Note that jars are casesensitive, make sure you the case-sensitive file-path.
Try any of these:
// using getResourceAsStream
InputStream is = this.getClass().getResourceAsStream( "picture.gif" );
// or
InputStream is = MyClass.class.getResourceAsStream( "stuff.ser" );
// or
InputStream is = MyApp.class.getClassLoader().getResourceAsStream( "InWords.properties" );
The resource in the jar file must be qualified with same package name as the class you call getResourceAsStream from. Alternatively, you can use an absolute name beginning with a / where dots get mapped to /s. If you don’t have a lead /, you have a relative name, and the name of the package will be prepended. If you use a /, you must include the name of the package yourself, or whatever name the resource is filed under in the jar.
For example you could specify /com/mindprod/mypackage/mystuff.ser or /com.mindprod.mypackage.mystuff.ser or simply mystuff.ser. Don’t use Windows style filenames with . These are not filenames, but Java resources that live along with the class files either in jars or sometimes freestanding on disk, or on the server.
In theory, getResourceAsStream will look in the local classpath, in the jar and in the directory where the class file was loaded from.
Related
After using images for example on a Button, when I build the application creating the .jar file and execute only the file, the images are not there but would only show if I copy the images folder in the same directory as the jar file. Why is that and how can I resolve this if possible?
I am currently using the following code to set the icon/image:
JButton btn = new JButton("Text", "img/icon.png");
The fact that you can use the images when they are stored outside the jar, suggests that you are doing something of the kind:
File image = new File("directory/image.jpg");
InputStream is = new FileInputStream(image);
This reads a file from a directory on the file system, not from the classpath. Now, if you have packaged your image in a "directory" inside your Jar, you must load the image from the classpath.
InputStream is = getClass().getResourceAsStream("/directory/image.jpg");
(note the slash in the path)
Or
InputStream is = getClass().getClassLoader().getResourceAsStream("directory/image.jpg");
(note the absence of the slash in the path)
Your example, as it is now, should not compile. (The second argument of your JButton construtor is an Icon, not a String, java 8). So when you were getting the image from the file system, you were probably doing something else.
With your example, you need to read an image from the inputstream and convert it to an Icon:
try (InputStream is = getClass.getClassLoader().getResourcesAsStream("directory/image.jpg")) {
BufferedImage image = ImageIO.read(is);
return new JButton("Text", new ImageIcon(image));
} catch (IOException exc) {
throw new RuntimeException(exc);
}
That should use the image that is located in "directory" inside your jar. Of course, you need to include the image within your jar, or you will get a NullPointerException on the inputstream is.
I think you need to understand the
ClassLoader:
A typical strategy is to transform the name into a file name and then
read a "class file" of that name from a file system.
So with this you will be able to lead Resources of your project with getResource
public URL getResource(String name)
Finds the resource with the given name. A resource is some data
(images, audio, text, etc) that can be accessed by class code in a way
that is independent of the location of the code.
I am trying to load an image to use as an icon in my application. The appropriate method according to this tutorial is:
protected ImageIcon createImageIcon(String path, String description)
{
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
So, I placed the location of the file, and passed it as a parameter to this function. This didn't work, i.e. imgURL was null. When I tried creating the ImageIcon by passing in the path explicitly:
ImageIcon icon = new ImageIcon(path,"My Icon Image");
It worked great! So the application can pick up the image from an explicitly defined path, but didn't pick up the image using getResources(). In both cases, the value of the path variable is the same. Why wouldn't it work? How are resources found by the class loader?
Thanks.
getClass().getResource(path) loads resources from the classpath, not from a filesystem path.
You can request a path in this format:
/package/path/to/the/resource.ext
Even the bytes for creating the classes in memory are found this way:
my.Class -> /my/Class.class
and getResource will give you a URL which can be used to retrieve an InputStream.
But... I'd recommend using directly getClass().getResourceAsStream(...) with the same argument, because it returns directly the InputStream and don't have to worry about creating a (probably complex) URL object that has to know how to create the InputStream.
In short: try using getResourceAsStream and some constructor of ImageIcon that uses an InputStream as an argument.
Classloaders
Be careful if your app has many classloaders. If you have a simple standalone application (no servers or complex things) you shouldn't worry. I don't think it's the case provided ImageIcon was capable of finding it.
Edit: classpath
getResource is—as mattb says—for loading resources from the classpath (from your .jar or classpath directory). If you are bundling an app it's nice to have altogether, so you could include the icon file inside the jar of your app and obtain it this way.
As a noobie I was confused by this until I realized that the so called "path" is the path relative to the MyClass.class file in the file system and not the MyClass.java file. My IDE copies the resources (like xx.jpg, xx.xml) to a directory local to the MyClass.class. For example, inside a pkg directory called "target/classes/pkg. The class-file location may be different for different IDE's and depending on how the build is structured for your application. You should first explore the file system and find the location of the MyClass.class file and the copied location of the associated resource you are seeking to extract. Then determine the path relative to the MyClass.class file and write that as a string value with "dots" and "slashes".
For example, here is how I make an app1.fxml file available to my javafx application where the relevant "MyClass.class" is implicitly "Main.class". The Main.java file is where this line of resource-calling code is contained. In my specific case the resources are copied to a location at the same level as the enclosing package folder. That is: /target/classes/pkg/Main.class and /target/classes/app1.fxml. So paraphrasing...the relative reference "../app1.fxml" is "start from Main.class, go up one directory level, now you can see the resource".
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("../app1.fxml"));
Note that in this relative-path string "../app1.fxml", the first two dots reference the directory enclosing Main.class and the single "." indicates a file extension to follow. After these details become second nature, you will forget why it was confusing.
getResource by example:
package szb.testGetResource;
public class TestGetResource {
private void testIt() {
System.out.println("test1: "+TestGetResource.class.getResource("test.css"));
System.out.println("test2: "+getClass().getResource("test.css"));
}
public static void main(String[] args) {
new TestGetResource().testIt();
}
}
output:
test1: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
test2: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
getResourceAsStream() look inside of your resource folder. So the fil shold be placed inside of the defined resource-folder
i.e if the file reside in /src/main/resources/properties --> then the path should be /properties/yourFilename.
getClass.getResourceAsStream(/properties/yourFilename)
I'm trying to figure out how to add a lot of images into my Java program without having to add every file name in the code.
So I want to take all the .png images in the correct folder and make them into an IconImage and then place them in an ArrayList.
What I've got right now is this.
private void fillList()
{
File[] files = new File("C:/Users/marre/Google Drive/Java/lek/imageplay/src/img").listFiles();
for (File f : files)
{
if (f.isFile())
{
ImageIcon tempIcon = new ImageIcon(getClass().getResource("/img/"+f.getName()));
List.add(tempIcon);
}
}
}
This works the way I want it to regarding getting the names of all images. But the file only reads from absolute file path.
What can I use instead to get the same result, but that works within .jar file (so it reads from src/img/ and not the whole c:/ bla bla..)?
I'm not sure if this will be helpful but I had a similar issue in attempting to obtain files within a jar file. In the case this can be useful to you, my approach was to obtain the URL for the files inside the jar using the ClassLoader:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("src/img/");
Check inside your jar to make sure of the directory structure for the images so you can specify the correct relative path.
Keep in mind, a jar is a packaged form, so this will most likely return a zipped file (and not a simple File object). You might have to dabble in ZipFile.
ZipFile folderInsideJar = new ZipFile(new File(url.getPath());
Enumeration<? extends ZipEntry> entries = folderInsideJar.entries();
while (entries.hasMoreElements()) {
// ideally this would be your image file, zipped
ZipEntry childFile = entries.nextElement();
// ... etc ...
}
For environments such as JBoss, etc, you might also get virtual files (vfsfile/vfszip). Point being, you can determine what you are dealing with by looking at the result URL.getProtocol().
It would also appear ImageIcon has a constructor that takes a URL. You might try giving this a shot to see if it handles the "resource inside jar" case before manually attempting to retrieve the zip file.
I have a Java project called MyProject. I have a few different packages (keeping names simple for the purpose of this question), as follows:
src/PackageA
src/PackageA/PackageAa
src/PackageA/PackageAa/PackageAaa
src/PackageB
src/PackageB/PackageBa
src/PackageB/PackageBa/PackageBaa
I have a class
src/PackageA/PackageAa/PackageAaa/MyJavaFile.java
And I have an image
src/PackageB/PackageBa/PackageBaa/MyImage.png
Inside of MyJavaFile.java, I would like to declare an Image oject of MyImage.png
Image img = new Image(....what goes here?...)
How can I do this?
You could either call Class.getResource and specify a path starting with /, or ClassLoader.getResource and not bother with the /:
URL resource = MyJavaFile.class
.getResource("/PackageB/PackageBa/PackageBaa/MyImage.png");
or:
URL resource = MyJavaFile.class.getClassLoader()
.getResource("PackageB/PackageBa/PackageBaa/MyImage.png");
Basically Class.getResource will allow you to specify a resource relative to the class, but I don't think it allows you to use ".." etc for directory navigation.
Of course, if you know of a class in the right package, you can just use:
URL resource = SomeClassInPackageBaa.class.getResource("MyImage.png");
(I'm assuming you can pass a URL to the Image constructor in question. There's also getResourceAsStream on both Class and ClassLoader.)
you can use relative path since the the relative path is project folder.
ImageIcon img = new ImageIcon("src/PackageB/PackageBa/PackageBaa/MyImage.png");
/folderB/folderBa/folderBaa/MyImage.png
The image can stored into a project folder location .eg: /images/MyImage.png
Then try:
Image img = new Image(/images/MyImage.png);
Using a file path is not possible when running a program that's in a jar file, especially if the program is being loaded as an applet or WebStart application then you can use ClassLoader to get image.
use the following code to load the images:
ClassLoader cldr = this.getClass().getClassLoader();
java.net.URL imageURL = cldr.getResource("/PackageB/PackageBa/PackageBaa/MyImage.png");
ImageIcon aceOfDiamonds = new ImageIcon(imageURL);
This IS the best way to handle all images and icons in a JAR App.
Once you've zipped up all of your images and icons into its own JAR file - Configure your build path by adding the images JAR file into your libraries tab so that its now included in your classpath.
Then simply use the following 3x lines of code at the start of your constuctor to access any image you need for anything including a SystemTray image which doesn't accept the simple ImageIcon's as its main icon (weird I know). The 3x lines are:
URL iconUrl = this.getClass().getResource("/image-iconb.png");
Toolkit tk = this.getToolkit();
imageIcon = tk.getImage(iconUrl);
(imageIcon is just a constructor declared Image variable)
Now you can set a window icon as simply as:
setIconImage(imageIcon );
and at the same time use the same variable when setting the System TrayIcon by declaring:
trayIcon = new TrayIcon(imageIcon, "SystemTray Demo", popupMenu);
The above allows you to declare Images or ImageIcons easily and centrally without running the risk of not keeping image resources in the right place. It keeps it nice and tidy, with the JAR containing all your images automatically compiled at run time and distribution of your program.
As a bonus, once the JAR is registered in your classpath - you can keep adding any other images into the same JAR at any time without any fuss too - Everything just works and the added images are instantly available to your app.
Much better in my view.
Use the getResource method to read resources inside the src root. For example, the following code retrieves images from a folder src/images.
// Get current classloader
ClassLoader cl = this.getClass().getClassLoader();
// Create icons
Icon saveIcon = new ImageIcon(cl.getResource("images/save.gif"));
Icon cutIcon = new ImageIcon(cl.getResource("images/cut.gif"));
The example assumes that the following entries exist in the application's JAR file:
images/save.gif
images/cut.gif
Image img = new Image("./src/PackageB/PackageBa/PackageBaa/MyImage.png");
This shall go the path of the image is first inside src (source) then package so the program would access the image this way.
I have an I18n helper class that can find out the available Locales by looking at the name of the files inside the application's Jar.
private static void addLocalesFromJar(List<Locale> locales) throws IOException {
ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();
JarInputStream jar = new JarInputStream(url.openStream());
while (true) {
JarEntry entry = jar.getNextJarEntry();
if (entry == null) {
break;
}
String name = entry.getName();
// ...
}
}
Currently, this isn't working - jar.getNextJarEntry() seems to always return null. I have no idea why that's happening, all I know is that url is set to rsrc:./. I have never seen that protocol, and couldn't find anything about it.
Curiously, this works:
class Main {
public static void main(String[] args) {
URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
JarInputStream jar = new JarInputStream(url.openStream());
while (true) {
JarEntry entry = jar.getNextJarEntry();
if (entry == null) {
break;
}
System.out.println(entry.getName());
}
}
}
In this version, even though there is practically no difference between them, the url is correctly set to the path of the Jar file.
Why doesn't the first version work, and what is breaking it?
UPDATE:
The working example really only works if I don't use Eclipse to export it. It worked just fine in NetBeans, but in the Eclipse version the URL got set to rsrc:./ too.
Since I exported it with Package required libraries into generated JAR library handling, Eclipse put its jarinjarloader in my Jar so I can have all dependencies inside it. It works fine with the other settings, but is there any way to make this work independently of them?
Another question
At the moment, that class is part of my application, but I plan to put it in a separate library. In that case, how can I make sure it will work with separate Jars?
The problem is the jarinjarloader ClassLoader that is being used by Eclipse. Apparently it is using its own custom rsrc: URL scheme to point to jar files stored inside the main jar file. This scheme is not understood by your URL stream handler factory, so the openStream() method returns null which causes the problem that you're seeing.
This answers the second part of your question about separate jars - not only will this work, it's the only way that it will work. You need to change your main application to use separate jars instead of bundling them all up inside the main jar. If you're building a web application, copy them into the WEB-INF/lib directory and you're fine. If you're building a desktop application, add a relative path reference in the META-INF/MANIFEST.MF to the other jars, and they will automatically be included as part of the classpath when you run the main jar.
The code may or may not result into the jar file where I18n resides. Also getProtectionDomain can be null. It depends how the classloader is implemented.
ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();
about the rsrc:./ protocol, the classloader is free to use whatever URL they please (or name it for that matter)
try this out, you might get lucky :)
URL url = getClass().getResource(getClass().getSimpleName()+".class");
java.net.JarURLConnection conn = (java.net.JarURLConnection) url.openConnection();
Enumeration<JarEntry> e = conn.getJarFile().entries();
...
and good luck!
Eclipse's jarinjarloader loads everything using the system classloader and it never knows what jar file it was loaded from. That's why you can't get the jar URL for a rsrc: url.
I suggest storing the list of locales in a file in each application jar, e.g. META-INF/locales. Then you can use ClassLoader.getResources("META-INF/locales") to get the list of all the files with that name in the classpath and combine them to obtain the full list of locales.
I use System.getProperty("java.class.path") for getting the location of the jar. I do not know if that makes a difference. I have not explored the ProtectDomain path so I cannot help you there, sorry. As for multiple jars, just iterate through those jar file also.