Deploying images used in Java Application with the built jar file - java

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.

Related

store file in spring boot resource folder after deployment

I have deployed a spring-boot application JAR file. Now, I want to upload the image from android and store it in the myfolder of resource directory. But unable to get the path of resource directory.
Error is:
java.io.FileNotFoundException: src/main/resources/static/myfolder/myimage.png
(No such file or directory)
This is the code for storing the file in the resource folder
private final String RESOURCE_PATH = "src/main/resources";
String filepath = "/myfolder/";
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file);
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
UPDATED:
This is what I have tried
private final String RESOURCE_PATH = "config/";
controller class:
String filepath = "myfolder/";
String filename = "newfile.png"
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
//reading old file
System.out.println(Files.readAllBytes(Paths.get("config","myfolder","oldfile.png"))); //gives noSuchFileException
//writing new file
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file); //FileNotFoundException
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
Project structure:
+springdemo-0.0.1-application.zip
+config
+myfolder
-oldfile.png
-application.properties
+lib
+springdemo-0.0.1.jar
+start.sh
-springdemo-0.0.1.jar //running this jar file
Usually when you deploy an application (or start it using Java), you start a JAR file. You don't have a resource folder. You can have one and access it, too, but it certainly won't be src/main/resources.
When you build your final artifact (your application), it creates a JAR (or EAR or WAR) file and your resources, which you had in your src/main/resources-folder, are copied over to the output directory and included in the final artifact. That folder simply does not exist when the application is run (assuming you are trying to run it standalone).
During the build process target/ is created and contains the classes, resources, test-resources and the likes (assuming you are building with Maven; it is a little different if you build using Gradle or Ant or by hand).
What you can do is create a folder e.g. docs next to your final artifact, give it the appropriate permissions (chmod/chown) and have your application output files into that folder. This folder is then expected to exist on the target machine running your artifact, too, so if it doesn't, it would mean the folder does not exist or the application lacks the proper permissions to read from / write to that folder.
If you need more details, don't hesitate to ask.
Update:
To access a resource, which is bundled and hence inside your artifact (e.g. final.jar), you should be able to retrieve it by using e.g. the following:
testText = new String(ControllerClass.class.getResourceAsStream("/test.txt").readAllBytes());
This is assuming your test.txt file is right under src/main/resources and was bundled to be directly in the root of your JAR-file (or target folder where your application is run from). ControllerClass is the controller, which is accessing the file. readAllBytes just does exactly this: read all the bytes from a text file. For accessing images inside your artifact, you might want to use ImageIO.
IF you however want to access an external file, which is not bundled and hence not inside your artifact, you may use File image = new File(...) where ... would be something like "docs/image.png". This would require you to create a folder called docs next to your JAR-artifact and put a file image.png inside of it.
You of course also may work with streams and there are various helpful libraries for working with input- and output streams.
The following was meant for AWT, but it works in case you really want to access the bytes of your image: ImageIO. In a controller you usually wouldn't want to do that, but rather have your users access (and thus download) it from a given available folder.
I hope this helps :).

How to get .jar resources path?

I'm using a custom method to get pictures from the resources/ folder. The hardcoded path works well when programming during production (src/main/resources/). However when delivering, I would need to make this path relative to the .jar root. So I made this.
public static Image getImageFromFile(String file)
{
Image image = null;
try
{
String path = FileUtils.class.getClassLoader().getResource(file).toExternalForm();
System.out.println(path);
File pathToFile = new File(path);
image = ImageIO.read(pathToFile);
}
catch (IOException ex) {ex.printStackTrace();}
return image;
}
file:/C:/Users/Hugo/Desktop/Hugo/Java%20Workspace/ClashBot/bin/main/icons/level-label.png
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at com.lycoon.clashbot.utils.FileUtils.getImageFromFile(FileUtils.java:55)
The printed path is valid and points to the corresponding picture. However, the program raises an IOException.
Why can't it find the file?
You're jumping through way too many hoops. It's quite simple:
FileUtils.class.getResource("path.png");
// -OR-
try (var in = FileUtils.class.getResourceAsStream("path.png")) {
// in is an inputstream.
}
is all you need. Note that this means the path.png file is searched for in the exact same place (and even same 'subdir') as where FileUtils lives. So if you have, say, a file on C:\Projects\Hugo\MyApp\myapp.jar, and if you were to unzip that, inside you'd find com/foo/pkg/FileUtils.class, then the string path.png would look in that jar, and for com/foo/pkg/path.png. In other words, AnyClass.class.getResource("AnyClass.class") will let a class find its own class file. If you want to go from the 'root' of the jar, add a slash, i.e. FileUtils.class.getResource("/path.png") looks in the same jar, and for /path.png inside that jar.
getResource returns a URL. getResourceAsStream returns a stream (which you need to close; use try-with-resources as I did). Just about every resource-using API out there will take one of these two as input. For example, ImageIO does so; it even takes a URL so you can use either one:
var image = ImageIO.read(FileUtils.class.getResource("imgName + ".png"));
Yes. It's a one-liner. This will load images straight from within a jar file!
You could try to use a slightly different call like this:
java.net.URL fileUrl = Thread.currentThread().getContextClassLoader().getResource(file);
String filePath = URLDecoder.decode(fileUrl.getPath(), "UTF-8");
image = ImageIO.read(filePath);

java.lang.NullPointerException when using getClass().getResource() to load an image [duplicate]

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)

javafx - load image from within a jar

I'm sorry for asking such a beginner question, but I just can't get it to work and I can't find the answer anywere either.
I want to have an image inside my .jar file and load it. While that sounds simple, I was only able to load an image while running from inside the IDE but not anymore after making the .jar (Thanks to google I was able to get the .png inside the .jar). Here is what I tried:
BorderPane bpMain = new BorderPane();
String fs = File.separator;
Image imgManikin;
try {
imgManikin = new Image(
Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toString()+"\\manikin.png");
bpMain.setBottom(new Label(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toString()+"\\manikin.png"));
} catch (URISyntaxException e) {
imgManikin = new Image(
Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png");
System.out.println(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png");
bpMain.setBottom(new Label(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png"));
}
//Image imgManikin = new Image("file:src\\manikin.png");
ImageView imgvBackground = new ImageView(imgManikin);
imgvBackground.setFitWidth(100);
imgvBackground.setPreserveRatio(true);
bpMain.setCenter(imgvBackground);
primaryStage.setTitle("Kagami");
primaryStage.setScene(new Scene(bpMain, 300, 275));
primaryStage.show();
Needlessly to say it didn't work. It is showing me the Label at the bottom with the path just as intended, but it seams like the path just isn't right. (I also tried using the File.seperator instead of \\ and even /, but I got the same result every time: It showes me the path but won't load the image.
I'm using Windows 7, the IDE is IntelliJ and I have the newest Java update.
If the jar file is on the classpath of your application and the image to be loaded is located at the root of the jar file, the image can be loaded easily by:
URL url = getClass().getResource("/manikin.png");
BufferedImage awtImg = ImageIO.read(url);
Image fxImg = SwingFXUtils.toFxImage(awtImg, new Image());
Image fxImgDirect = new Image(url.openStream());
While ImageIO returns a BufferedImage this can be converted to a fx Image using the SwingUtils. However the preferred way is to directly create a new Image instance using the InputStream from the URL.
See also Load image from a file inside a project folder. If done right it does not matter if it is loaded from a jar file or the local file system.
The Image::new(String) constructor is looking for a URL. It is possible to construct a URL for a resource in a jar file, but it's much easier to use ClassLoader::getResource or ClassLoader::getResourceAsStream to manage that for you.
Given the file structure:
src/
SO37054168/
GetResourceTest.java
example/
foo.txt
The following, packaged as a jar will output
package SO37054168;
public class GetResourceTest {
public static void main(String[] args) {
System.out.println(GetResourceTest.class.getClassLoader().getResource("example/foo.txt"));
System.out.println(GetResourceTest.class.getClassLoader().getResourceAsStream("example/foo.txt"));
}
}
jar:file:/home/jeffrey/Test.jar!/example/foo.txt
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream#7f31245a
Note how the URL for the resource is not the same as the URL you were trying to construct. The protocol is different, and you need to have the ! after the path to the jar file.

Make all images in a folder into IconImages

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.

Categories

Resources