-1

please guys i want to load images from i jar in a javafx app but it don't show up even though it works in ide just as expected this is the output i get from load function file:/C:/Users/anass/OneDrive/Desktop/anass_coder/target/classes/com/anass/anass_code_editor/assets/languages/ and this is the absolute path of images folder C:\Users\anass\OneDrive\Desktop\anass_coder\src\main\resources\com\anass\anass_code_editor\assets\languages

this is the load function :

public static void loadIconImages() {
        iconImages = new HashMap<>();
        URL imagesDirURL = App.class.getResource("/com/anass/anass_code_editor/assets/languages");
        if (imagesDirURL != null) {
            System.out.println(imagesDirURL.toExternalForm());
            try {
                InputStream imagesDirStream = imagesDirURL.openStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(imagesDirStream));
                String line;
                while ((line = reader.readLine()) != null) {
                    String name = line.trim().toLowerCase();
                    if (name.contains(".")) {
                        String resourcePath = "/com/anass/anass_code_editor/assets/languages/" + name;
                        InputStream imageStream = App.class.getResourceAsStream(resourcePath);

                        if (imageStream != null) {
                            iconImages.put(name.substring(0, name.indexOf(".")), new Image(imageStream));
                            imageStream.close();
                        }
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            System.out.println("No dir");
        }
    }

i am using maven to bundle the desktop app

i tried getRessourcesAsStream ,the uri is not hirarchicall error is gone but ressources are not found the ressources are well bundled and exist in jar archive

forty-two
  • 12,204
  • 2
  • 26
  • 36
  • Try removing the leading slash, I don't believe an absolute reference here is correct. – Rogue Sep 01 '23 at 16:03
  • If you're going to be dynamic about the names of the resources, you will have to start by reading them out of a *file resource (in the jar)*, such a `/resource.names.txt` – g00se Sep 01 '23 at 16:22
  • This should do it for you: `Map resourceMap = new HashMap<>();try (BufferedReader in = new BufferedReader(new InputStreamReader(X.class.getResourceAsStream("/resource-names.txt")))) {in.lines().forEach(res ->resourceMap.put(res, new Image(X.class.getResource(res))));}` – g00se Sep 01 '23 at 16:37
  • "*this is the absolute path of images folder*" only before it is put into the JAR - and not really relevant - the path inside the JAR counts! (you can open a JAR using 7-zip, WinZip or `jar.exe tvf file.jar` that comes with the JDK) – user22471702 Sep 01 '23 at 16:55
  • 2
    @Rogue it _is_ correct. You might want to review the javadoc. It's a bit tricky; `ClassLoader` has a `getResource` method that must not be given any leading slashes, whereas `j.l.Class` instances _also_ have `getResource`, which are relative to the class you call it on, _unless_ you use a leading slash. – rzwitserloot Sep 01 '23 at 17:36

1 Answers1

3

You're asking for a directory name as a resource. This is unsupported and usually does not work. It should never work but the spec doesn't promise 'does not work' either. Point is, don't - it doesn't (always) work and is therefore useless. You then try to read this dir as a file (as a stream of bytes), hoping that somehow it will produce a list of file names. That doesn't work either. Or rather, it shouldn't - no spec claims that this is what must happen, and therefore, JVMs are free not to do that.

The simple conclusion is that the concept of resource loading does not support any list commands whatsoever. This code wants to load 'every resource in a folder', that's a list operation and thus cannot be written without hackery.

The common solution to this problem involves creating a file (that'd be a known name, so, can be read without a list primitive being available) that contains every file. You can then open the 'resource that contains a list' and then use that list - now you aren't relying on the loader system to list for you (which is good, because that's not something it can actually do).

Of course, maintaining that 'file containing a list of image resources' is a pain. So, we fixed the problem but this fix introduces a new problem. One way to solve that problem is to have the file containing the names of all images be generated automatically during the build. Annotation processors can do it, so can build plugins. But, for now, first things first: Write out the list of all images by hand, stick it in a known place, read that file with .getResourcesAsStream, and use that to loop and load every image.

Once that works you may want to ask a separate question showing that code and explaining that this works as is but that you're looking for a way to have the 'file containing the name of every image file' be generated automatically during builds.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • In a modular application, you actually can do `Module m = App.class.getModule(); try (ModuleReader reader = m.getLayer().configuration().findModule(m.getName()).get().reference().open()) { reader.list().filter(e -> e.startsWith("com/anass/anass_code_editor/assets/languages/")).forEach( /* ... */ ); }`. I don’t think there’s any way to do it in an unnamed module, though. Also this obviously isn’t very efficient in large modules. – VGR Sep 02 '23 at 00:06
  • thank you very much i included a list of files instead and it works! – anass dabgahi Sep 02 '23 at 18:17