Preferred way of loading resources in Java
Work out the solution according to what you want...
There are two things that getResource
/getResourceAsStream()
will get from the class it is called on...
- The class loader
- The starting location
So if you do
this.getClass().getResource("foo.txt");
it will attempt to load foo.txt from the same package as the "this" class and with the class loader of the "this" class. If you put a "/" in front then you are absolutely referencing the resource.
this.getClass().getResource("/x/y/z/foo.txt")
will load the resource from the class loader of "this" and from the x.y.z package (it will need to be in the same directory as classes in that package).
Thread.currentThread().getContextClassLoader().getResource(name)
will load with the context class loader but will not resolve the name according to any package (it must be absolutely referenced)
System.class.getResource(name)
Will load the resource with the system class loader (it would have to be absolutely referenced as well, as you won't be able to put anything into the java.lang package (the package of System).
Just take a look at the source. Also indicates that getResourceAsStream just calls "openStream" on the URL returned from getResource and returns that.
Groovy: Preferred Way to Handle Classpath Resource Loading
Answers in turn;
1:
String xsd = this.getClass().getResource('/xsd/file.xsd').text
And 2:
No. But there's a library that makes it easy
Best way to handle resource files in Java so that they work in Eclipse and when packaged into a jar?
I would recommend using Apache Maven. This tool can automatically JAR up your project and include your resources. They have a quick tutorial on Maven in 5 minutes. Then all you need to do is place your resources in src.main.resources
and it should automatically included in the jar (see the Getting Started Guide) for more details.
Hope this helps!
Update
As for getting the resource from here, have you tried getResourceAsStream()
from the Java file?
java - How to have a resource file
In general, unless you have good reason to, you probably don't need to overwrite maven's default configuration.
Maven uses a "convention over configuration" philosophy, meaning it:
- assumes sensible default values for properties
- allows you to overwrite this if you need to
So, if you want a resource folder, maven provides one for you by default (assuming you follow the default project structure)
You should have a resource folder at src/main/resources
, with your Java code in src/main/java/<package-name>
. This is the default structure that maven expects.
From there you can get a reference to this by using Class.getResource()
. For example, if you have a file in src/main/resources/file.txt
, you can access it with getClass().getResource("/file.txt")
(note the leading slash).
However, if you want to modify this during runtime (perhaps if a user wants to save new details), you should not use resources. Instead, consider one of the following:
- File in current directory - just use
new File("config.txt")
and read/write to that - File in user home directory - use
new File(System.getProperty(user.home), "config.txt")
. On Windows for example this creates a file atC:/users/<username>/config.txt
. - Database - If your application already uses a database, it can be a good place to store a lot of configuration options, although, based on your question, I imagine this is not suitable for you.
How to Properly Get a File from resources Folder
Test.class.getClassLoader();
obtains a reference to the ClassLoader
class from the Class
' method public ClassLoader getClassLoader()
- see private final ClassLoader classLoader
below.
Since you are accessing the ClassLoader
class from an object of that class, you're not accessing it in a static way.
From Class.java
, Java SE 1.7:
@CallerSensitive
public ClassLoader getClassLoader() {
ClassLoader cl = getClassLoader0();
if (cl == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
}
return cl;
}
// Package-private to allow ClassLoader access
ClassLoader getClassLoader0() { return classLoader; }
// Initialized in JVM not by private constructor
// This field is filtered from reflection access, i.e. getDeclaredField
// will throw NoSuchFieldException
private final ClassLoader classLoader;
In order to access the method in a static way, it has to be called from the class which declares it as static if you want to get rid of the warning:
ClassLoader.getSystemResource("test.html").getFile()
To avoid the NPE the test.html
file should be under your source folder.
To respond to your comment, using a method which returns other than a URL
solves your problem - see Reading a resource file from within jar.
public class Test {
public static void main(String[] args) {
StringBuilder contentBuilder = new StringBuilder();
InputStream is = Test.class.getResourceAsStream("/test.html");
try {
String sCurrentLine;
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
while ((sCurrentLine = buffer.readLine())!=null)
contentBuilder.append(sCurrentLine);
buffer.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
System.out.println("content=" + contentBuilder.toString());
}
}
Loading resource files within a jar
This snippet of code worked for me:
Clip clip = null;
ClassLoader cl = this.getClass().getClassLoader();
AudioInputStream ais;
URL url = cl.getResource("com/example/project/assets/TestSound.wav");
System.out.println(url);
try {
ais = AudioSystem.getAudioInputStream(url);
clip = AudioSystem.getClip();
clip.open(ais);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
The important thing is not adding the /src/
folder to the class path.
The critical change is changing cl.getResource("/com/example/project/assets/TestSound.wav")
to cl.getResource("com/example/project/assets/TestSound.wav");
because /com/...
indicates that the path is absolute, whereas com/...
indicates that the path is relative.
For example,
System.out.println(new File("/Test.File").getAbsolutePath());
System.out.println(new File("Test.File").getAbsolutePath());
return
/Test.File
/Users/alphadelta/Documents/Workspace/TestProject/Test.File
respectively.
The first File created is created using "/Test.File"
, which is absolute. The second is created using "Test.File"
, which is relative to the project root in eclipse.
Class.getResource and ClassLoader.getSystemResource: is there a reason to prefer one to another?
There are several ways to load resources, each with a slightly different meaning -
ClassLoader::getSystemResource()
uses the system classloader. This uses the classpath that was used to start the program. If you are in a web container such as tomcat, this will NOT pick up resources from your WAR file.
Class<T>#getResource()
prepends the package name of the class to the resource name, and then delegates to its classloader. If your resources are stored in a package hierarchy that mirrors your classes, use this method.
ClassLoader#getResource()
delegates to its parent classloader. This will eventually search for the resource all the way upto the system classloader.
If you are confused, just stick to ClassLoader#getResource()
Using the ClassLoader method to retrieve all resources under classes as Input Streams
You can do that with some tricks :)
Get the resource as URL, extract the protocol :
- file protocol - get the URL path and you have a folder, scan for files.
- jar/zip protocol - extract the jar/zip path and use JarFile to browse the files and extract everything under your path/package.
Related Topics
Connecting to Remote Url Which Requires Authentication Using Java
How to Resolve Java Unknownhostkey, While Using Jsch Sftp Library
Jar Bundler Using Osxadapter Causing Application to Lag or Terminate
Should a Retrieval Method Return 'Null' or Throw an Exception When It Can't Produce the Return Value
Why Are Filenames in Java the Same as the Public Class Name
How to Map an Entity Field Whose Name Is a Reserved Word in JPA
How to Switch Between Frames in Selenium Webdriver Using Java
Tomcat 10.0.4 Doesn't Load Servlets (@Webservlet Classes) with 404 Error
Add Image Thumbnails to a Layout in a Grid
What Exactly Is Field Injection and How to Avoid It
Java - Best Approach to Parse Huge (Extra Large) JSON File
Nosuchmethoderror in Javax.Persistence.Table.Indexes()[Ljavax/Persistence/Index
Java 8: Difference Between Two Localdatetime in Multiple Units
How to Derive Module Descriptor for Auto Generated Module Names in Java 9
How to Convert Strings to and from Utf8 Byte Arrays in Java
How to Create a Jar with External Libraries Included in Eclipse