Home > Blockchain >  java jar - how do I specify where resources should be saved?
java jar - how do I specify where resources should be saved?

Time:04-29

Here's my current pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hu.elte.inf</groupId>
    <artifactId>ThesisMVN</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- Build an executable JAR -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>main/Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.javatuples</groupId>
            <artifactId>javatuples</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
</project>

I need the structure of my resources folder (and its subfolders) maintained, as currently takes them out of resources folder, so my game can't start because it can't find all the textures.
resource structure within the project
resource structure within the project
jar-ed resource structure (note that only one effects folder is in the jar, it put the images next to the class file here)
jar-ed resource structure

Here's how I'm currently loading Images

public class ResourceLoader {
    public static Image getResource(String path){
        Image img=null;
        try{
           img = ImageIO.read(new File(path));
        }
        catch(IOException e) {
            System.err.println("File not found(" path ')');
            e.printStackTrace();
        }
        return img;
    }
}

The path passed to getResource is acquired from an enum where I set the path of all of my Images, like this:

...
BULLET("src/main/resources/bullet.png"),
BULLET_GREY("src/main/resources/bullet_grey.png"),
...
AOE_SLOW("src/main/resources/effects/aoeSlow.png"),
AOE_DISARM("src/main/resources/effects/aoeDisarm.png"),
...

I assume I should drop the src/main/resources prefixes, but then I can onyl reach the Images once the project is jarred up.

This may be the wonky part of my setup but I'm currently storing every loaded Image in a class called GameStateData. Whenever I need to create a new Sprite I just get the already loaded Image from there, so I only need to load every Image just once when launching the game.

CodePudding user response:

I need the structure of my resources folder (and its subfolders) maintained

It IS maintained. Every file and directory in your resources folder has been dutifully copied straight into the jar as the Standard Directory Layout dictates.

The problem is your setup: At 'dev time' you appear to attempt to load from resources/items/someItem.png and this doesn't work when your app is jarred up. There are 2 obvious ways this can be happening;

You're confused about the reason

You're trying to use new FileInputStream, new File, or otherwise are attempting to load these as files. This does not work and cannot work and no amount of futzing with directory structures will ever make it work. In java, file means file - and a png entry in a jarfile is not itself a file.

The way to load such resources is, always, this strategy:

  1. Pick a class that is the 'source location' - as in, the resource you're looking for will be where-ever the JVM found this class file. Generally you can pick any class in your entire application; this is relevant only when you use modularized class loading systems. If you don't know what that means, you're not using those.

  2. Call MyContextClass.class.getResource(resourceKey) to obtain a URL object, which you can then pass to whatever API allows you to do that (and lots of APIs do, notably including swing's own ImageIcon). Alternatively, use try (var in = MyContextClass.class.getResourceAsStream(resourceKey) { /* use resource here */ } - this is the one to use if the API in question doesn't have an overload that takes a URL but does have one that takes an InputStream. This is also the one to use if you want to directly read the contents.

  3. resourceKey comes in 2 flavours. There's "foo/bar.png" which resolves a path relative to the exact package your context class is in. If you have package com.foo; public class Bar {} then somewhere in the deployment there's com/foo/Bar.class. For example, in a jar file, or in a bin dir. If you then write Bar.class.getResource("baz/quux.png"), and Bar.class was in that jar file, then the system is going to look in the same jar file, for com/foo/baz/quux.png. Alternatively, include a leading slash: "/foo/bar.png" would look in the same jar, but for foo/bar.png.

  4. That's all you have to do. Build systems and IDEs ensure that you put your images exactly where you have them now (in a resources folder), you do not include resources in your deployment key (for the same reason you have your java source files in src/main/java/com/foo/MyApp.class, and you do not include src, main, or java in your fully qualified class names. It's just com.foo.MyApp, not main.java.com.foo.MyApp. The resources isn't a part of it any more than java is a part of your class names. If it doesn't work you've misconfigured them.

You've got a wonky setup

It's possible you've been hacking away and e.g. using a plugin system where you check for certain files either directly on the filesystem yourself, -OR- load via ContextClass.class.getResource, or you've been messing with the way your IDE's maven plugin identifies resource directories, or you've been handrolling the setup of your IDE projects (instead of using its maven integration) and marked src/main as source dir (instead of src/main/java and src/main/resources). The setup is broken; fix that (do not 'fix' it by trying to keep resources around).

  • Related