Load Resource from Anywhere in Classpath

Load resource from anywhere in classpath

If all else fails you could use two different file names, say props-default.properties inside myJar.jar and props.properties to override on the command-line. In your code, you'd try loading the props.properties file first and fallback to props-default.properties if it wasn't found.

can I load resource from classpath if set to any directory?

One thing to pay attention to when using getResourceAsStream is the format of the resource name that you are retrieving. By default if you do not specify a path, e.g., "autopublisherpath.cfg", the classloader will expect that the resource being specified is within the same package as the Class on which you executed the getResourcesAsStream method. The reason for this behavior can be found in the JVM documentation for getResourceAsStream:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
  • Otherwise, the absolute name is of the following form: modified_package_name/name

In your particular example, if the Config class was located in the com.test.config package, then the resource name of "autopublisherpath.cfg" would be converted to "/com/test/config/autopublisherpath.cfg" (period in package is replaced with a '/' character). As a result, keeping with your original project hierarchy, you would need to place the file into the location:

autopublisher/resources/config/com/test/config 

where autopublisher/resources/config was added as part of application's execution classpath.

If you are looking to add a specific config directory to your classpath and want the file to be located in the root of that directory, then you need to prefix the name of the file with a '/' character, which specifies that the resource should be in the root package of the classpath.

InputStream iStream = Config.class.getResourceAsStream("/autopublisherpath.cfg");

Using this code, you should be able to add the resource/config directory to your classpath and read the file as expected.

On a side note, the getResourceAsStream method loads the resource using the Classloader of the class from which it was executed (in this case Config). Unless your application uses multiple class loaders, you can perform the same function from any of your class instances using this.getClass().getResourceAsStream(...).

Accessing resource files from external modules

While you are using the java command to launch an application as follows:-

java -p target/classes:target/dependency -m framework.core/com.framework.Main 
  • you are specifying the modulepath using the option -p aternate for --module-path which would look up into target/classes and target/dependency for your modules.

  • Alongside, using -m alternate for --module specifies the initial module to resolve with the name framework.core and constructs the module graph with the main class to execute explicitly listed as com.framework.Main.

Now, the problem here seems to be that the module framework.core doesn't requires or read playground.api module because of which the module graph doesn't include the desired module consisting of the actual resource config.yml.

As suggested by @Alan, a good way to list out the module resolution output during startup is to make use of the --show-module-resolution option.


I just naively tried to opens src/main/resources, doesn't compile ofc

Since the resource in your module is at the root level, it is, therefore, not encapsulated and does not need to be opened or exported to any other module.

In your case, you just need to make sure that the module playground.api ends up in the module graph and then the resource would be accessible to the application. To specify root modules to resolve in addition to the initial module, you can make use of the --add-modules option.


Hence the overall solution to work for you along with some debugging shall be :

java --module-path target/classes:target/dependency 
--module framework.core/com.framework.Main
--add-modules playground.api
--show-module-resolution

Reading a file from a jar, or anywhere on the classpath?

I don't understand your problem. Resources from src/main/resources are automatically copied over to target/classes and are thus available on the classpath under Maven and Eclipse relatively to the root level at the same location (unless your Eclipse project is not properly configured).

And when packaged inside a JAR, the content of target/classes is packaged "as is" so nothing is changed.

In other words, accessing your file.txt like this is perfectly fine (and this is actually how things are documented):

// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/file.txt" );

// Do something with the resource

...

If you have a problem somewhere, please clarify.

Update: I did a quick test with the maven-eclipse-plugin and I can't reproduce your problem:

$ mvn archetype:generate -DgroupId=com.stackoverflow -DartifactId=q2467362 -Dversion=1.0-SNAPSHOT
...
$ cd q2467362
$ mkdir -p src/main/resources
$ mvn eclipse:eclipse
...
$ cat .classpath
<classpath>
<classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/>
<classpathentry kind="src" path="src/main/java" including="**/*.java"/>
<classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/>
<classpathentry kind="output" path="target/classes"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/3.8.1/junit-3.8.1.jar" sourcepath="M2_REPO/junit/junit/3.8.1/junit-3.8.1-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
</classpath>

The directory src/main/resources is added as source folder as expected. Can you show your POM (especially the resources element if you define one)?

How do I load a file from resource folder?

Try the next:

ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream("test.csv");

If the above doesn't work, various projects have been added the following class: ClassLoaderUtil1 (code here).2

Here are some examples of how that class is used:

src\main\java\com\company\test\YourCallingClass.java
src\main\java\com\opensymphony\xwork2\util\ClassLoaderUtil.java
src\main\resources\test.csv
// java.net.URL
URL url = ClassLoaderUtil.getResource("test.csv", YourCallingClass.class);
Path path = Paths.get(url.toURI());
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
// java.io.InputStream
InputStream inputStream = ClassLoaderUtil.getResourceAsStream("test.csv", YourCallingClass.class);
InputStreamReader streamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader);
for (String line; (line = reader.readLine()) != null;) {
// Process line
}

Notes

  1. See it in The Wayback Machine.
  2. Also in GitHub.

How to locate all resources in classpath with a specified name?

You can use Enumeration getResources(String name) on the class loader to achieve the same.

For example:

Enumeration<URL> enumer = Thread.currentThread().getContextClassLoader().getResources("/Path/To/xyz.properties");
while (enumer.hasMoreElements()) {
System.out.print(enumer.nextElement());
}

Java: Loading resources from the file system

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");


Related Topics



Leave a reply



Submit