Does Java getResource method only work with particular extensions? - java

The following piece of code works fine
getClass().getResource("/index.xml");
However when I do a full refactor to
getClass().getResource("/index.html");
The above line throws NullPointerException. I know I have refactored correctly because I rename the file using IDE smart refactor i.e. the file index.html definitely exists in the same directory. As soon as I switch back to
getClass().getResource("/index.xml");
Everything is fine again. Is there any reason why only the .xml extension works?

As #a_horse_with_no_name mentions, using getResourceAsStream( ) should work fine with any file and any extension.
I'd be inclined to believe (based on the information presented) that your IDE hasn't properly refreshed its file hierarchy after the refactor. I'd suggest running a full clean and build of your project, see if that helps the situation.

So, most of the other answers, the class/class loader shouldn't be looking at file extension You could write a ClassLoader which did that, but it would be odd.
I'm going to take a stab at what your problem is. I am guessing using some IDE (you don't specify which) that is copying certain files from your source folder into the destination (either a jar or a directory of classes and resources). For Java code, you want the compiled .class object files there and not the .java sources. So the IDE will be configured, with some reasonable default [magic], to copy files with only certain extensions. HTML files were used for old package JavaDocs (package-info.html rather than package-info.java which can include package-wide annotations), so are arguably reasonable to exclude by default.
Therefore, you should investigate what the project is doing in this area, and change any configurations accordingly.

Using getResourceAsStream() should work with any file extension (at least it does for me)

Recognised Java Resources are either a class extending ResourceBundle or .property file.
You can write your own extenstions to enable Resource to be gathered from other extensions.
I'm unsure why .xml files are a viable extension. Are you using Java 7?

From the JavaDoc guide:
The name of a resource is independent of the Java implementation; in
particular, the path separator is always a slash (/). However, the
Java implementation controls the details of how the contents of the
resource are mapped into a file, database, or other object containing
the actual resource.
A resource is identified by a string consisting of a sequence of
substrings, delimited by slashes (/), followed by a resource name.
Each substring must be a valid Java identifier. The resource name is
of the form shortName or shortName.extension. Both shortName and
extension must be Java identifiers.
And read this doc which tell us : an absolute resource name is constructed from the given resource name using this algorithm.

getResource() will work regardless of the type of resource. All it does it return a URL. This example works fine for me.
public class Example {
public static void main(String... args) {
System.out.println(Example.class.getResource("jaxb.properties"));
System.out.println(Example.class.getResource("test.xml"));
System.out.println(Example.class.getResource("foo.html"));
System.out.println(Example.class.getResource("danger.exe"));
}
}

Related

Using File in Java [duplicate]

I've created a jar-File with maven. When i open this jar i can find the following content:
my.jar
|_text1.txt
|_folder
|_ ... some other stuff
When i'm running this code snippet in Eclipse, content of "text1.txt" and all filenames from folder content where printed out
String tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("text1.txt"), StandardCharsets.UTF_8);
System.err.println(tmp);
tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder"), StandardCharsets.UTF_8);
System.err.println(tmp);
When i'm running this code as a standalone program, content from "text1.txt" will be printed as well, but the second part for folders returns null.
What am i doing wrong?
App.class.getClassLoader().getResourceAsStream
Don't do this. The right way is App.class.getResourceAsStream. There are times when getCLassLoader() returns null; in such cases, your strategy is broken, the above will work fine. Also, your way is more calls and more code for no gain.
IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder")
You can't get a 'folder'. What do you think this would even do? The abstraction designed into the resource loader system (which is what you're using here) doesn't let you get folders in any way, and does not allow you to list the contents of a folder either. (You're possibly looking for SPI: Service Provider Interface).
IOUtils
You do not need this; java.nio.file.Files is built-in, and has a toString method just the same. It even defaults to UTF-8 so you don't have to specify it.
App.class.getResourceAsStream("text1.txt")
This will look for t1.txt in the exact same place as App.class. Even the same package structure. If you want to go from the 'root' of where App.class is found (so, the thing on your -classpath, generally), put a slash in front: Ask for "/text1.txt" for example).
Given that you have text1.txt in the root, and not in com/foo/pkg next to com/foo/pkg/MyApp.class, you'd need to specify "/text1.txt" to find it.
If you're unsure about where this stuff is looking, sysout the result of this call:
App.class.getResource("App.class");
this prints a URL and from it your eyeballs will be able to tell where it's looking.
and all filenames from folder content where printed out
That's nice. This does not work - that eclipse gives you this at runtime is weirdness baked in, but the spec fundamentally has no abstraction for this. ClassLoader implementations can do whatever they want (it's a pluggable system) and the only method they need implement is 'find the resource at this location'. There is no obligation to return a string of filenames if you ask for a 'folder', and most classloaders (including the one reading jar files) simply don't.
The solution is SPI: At compile time make a file that lists paths or classnames, and then at runtime use the resource system to load the file, and then load every class / every resource listed inside it. An annotation processor can automate the process of generating this file as part of compilation, making the whole ordeal seamless. Search the web for SPI java for more.

How does ClassLoader.getResourceAsStream work?

I've created a jar-File with maven. When i open this jar i can find the following content:
my.jar
|_text1.txt
|_folder
|_ ... some other stuff
When i'm running this code snippet in Eclipse, content of "text1.txt" and all filenames from folder content where printed out
String tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("text1.txt"), StandardCharsets.UTF_8);
System.err.println(tmp);
tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder"), StandardCharsets.UTF_8);
System.err.println(tmp);
When i'm running this code as a standalone program, content from "text1.txt" will be printed as well, but the second part for folders returns null.
What am i doing wrong?
App.class.getClassLoader().getResourceAsStream
Don't do this. The right way is App.class.getResourceAsStream. There are times when getCLassLoader() returns null; in such cases, your strategy is broken, the above will work fine. Also, your way is more calls and more code for no gain.
IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder")
You can't get a 'folder'. What do you think this would even do? The abstraction designed into the resource loader system (which is what you're using here) doesn't let you get folders in any way, and does not allow you to list the contents of a folder either. (You're possibly looking for SPI: Service Provider Interface).
IOUtils
You do not need this; java.nio.file.Files is built-in, and has a toString method just the same. It even defaults to UTF-8 so you don't have to specify it.
App.class.getResourceAsStream("text1.txt")
This will look for t1.txt in the exact same place as App.class. Even the same package structure. If you want to go from the 'root' of where App.class is found (so, the thing on your -classpath, generally), put a slash in front: Ask for "/text1.txt" for example).
Given that you have text1.txt in the root, and not in com/foo/pkg next to com/foo/pkg/MyApp.class, you'd need to specify "/text1.txt" to find it.
If you're unsure about where this stuff is looking, sysout the result of this call:
App.class.getResource("App.class");
this prints a URL and from it your eyeballs will be able to tell where it's looking.
and all filenames from folder content where printed out
That's nice. This does not work - that eclipse gives you this at runtime is weirdness baked in, but the spec fundamentally has no abstraction for this. ClassLoader implementations can do whatever they want (it's a pluggable system) and the only method they need implement is 'find the resource at this location'. There is no obligation to return a string of filenames if you ask for a 'folder', and most classloaders (including the one reading jar files) simply don't.
The solution is SPI: At compile time make a file that lists paths or classnames, and then at runtime use the resource system to load the file, and then load every class / every resource listed inside it. An annotation processor can automate the process of generating this file as part of compilation, making the whole ordeal seamless. Search the web for SPI java for more.

How to correctly setup resources in a exportable library

In a library I made, I have the following line to retrieve my resources:
private static final File fragment = new File(DefaultShader.class.getClassLoader().getResource("file.txt").getFile());
But when I export this library to a JAR and attempt to use it in another application, when this same line is read internally I get an I/O error because it's trying to access the JAR.
java.io.FileNotFoundException: file:\C:\Users\me\test\libs\lib.jar!\file.txt
Nodejs would make this easier by providing methods that returns the runtime location path of a script, apparently there is not an equivalent in Java or just couldn't find it. How can I get around this issue?
Never call the getFile method of URL. It does not return a valid file name. It only returns the path portion of a URL.
A resource embedded in a .jar file is not a File and you cannot refer to it as a File.
Fortunately, you don’t need a File object. You can read it directly using getResourceAsStream:
DefaultShader.class.getResourceAsStream("/file.txt")
Obviously, you should not store an InputStream in a static final field. But you can easily make a method instead:
private static InputStream readFileData() {
return DefaultShader.class.getResourceAsStream("/file.txt");
}
Be aware that resources should be placed in packages, just like classes. Placing a resource in the root of a .jar is like writing a file to a drive’s root directory or the user’s home directory: if any other program chooses to use the same filename, the results for both programs will be problematic, to say the least.
Similarly, if your resource is in the root of your .jar, and another library also happens to store a resource with the same name in the root of its own .jar, there will be a conflict, and it may or may not be your resource which gets loaded by the getResource* methods, depending on the current classpath definition. (This concern doesn’t apply to Java 9+ modular programs, but it’s still a good idea to keep resources in packages.)
The practice of putting a resource in the same package as the class that uses it is considered a good practice by Java SE: the getResource and getResourceAsStream methods are designed to expect it in the same package as the class by default. If the string argument does not start with a slash, those methods assume it’s in the same package.
This looks for file.txt in the same package as the DefaultShader class:
DefaultShader.class.getResourceAsStream("file.txt")
Whereas this will look for file.txt in the root of every .jar in the classpath:
DefaultShader.class.getResourceAsStream("/file.txt")

File and bundleresource:// URLs

I've been breaking my head over this for quite a while now and cant find a solution for this problem:
I have an Eclipse RCP application that uses a custom library packaged as jar. From the plugin, i am calling a method within the jar.
Within this method, i am "getting" a resource using this.class.getResource(relPath), whereas relPath is a hardcoded relative path to a file i need. This returns me an URL which i can use to construct a File.
Now, this works perfectly if i am not calling this method from the plugin, but from a simple Java-Program.
The difference: Eclipse RCP's classloader returns an URL of protocol bundleresource:// which is not supported by File, whereas when running a simple Java-program, a file://-URL is returned which is completely fine to construct a File.
I am aware of the FileLocator-class of the Eclipse SDK (which resolves bundleresource-URLs to file-URLs), but i cannot use it within the library because i dont want to tie it to the Eclipse RCP platform - it should be possible to use this lib from non-Eclipse-RCP sources as well.
Anyone any idea on how i can load this resource from a relative path in a manner that will work both when the method is called from an Eclipse RCP-Plugin or any other client?
I need to construct a File on the directory of this relative path to search for files within. I am completely stuck on this...
UPDATE: If there is a possibility other than using File#list() to get directory contents this would already help me..
any hints greatly appreciated,
Couldn't you simply invert the dependency. I.e., your module retrieving the resource as URL defines an interface
interface Locator { URL resolve(URL url); }
and you can use a default implementation
class StandaloneLocator implements Locator {
public URL resolve(URL url) { return url; }
}
In case of Eclipse, this default locator is to be replaced by
class EclipseLocator implements Locator {
public URL resolve(URL url) { return FileLocator.resolve(url); }
}
Now, your library has no dependencies to Eclipse, and you can still use the FileLocator. Since you won't get any bundleresource-URLs w/o Eclipse, this should work.
Cheers,
Jens
That is not possible to enumerate files in jar file using methods from Class. You either need to create resourcelist file which will contain all your resources names, or open jar file like zip archive and enumerate files like in zip archive. File class can not handle protocols other than file://. If your rescource is in jar file, you should use Url class and get stream using Url.openSteram method to get file contents.
UPD regarding running simple java application: you probably does not pack it into jar file, so your classes and resources are placed in file system and not in archive. That is why you get file:// protocol. If you pack into jar file, protocol will not be file:// it will be jar:// (not sure about exact protocol name).

Java Properties File not loading

I need a configuration file in my program to store some information, I saw some examples of properties files and was trying to use them but whenever I try this second line on NetBeans i get 'Package sortConfig doesn't exist' '<identifier> Expected' and 'Illegal start of type'.
The problem is I already saw some 10 examples all doing this in the same way, and I have no clue to what's going on.
Properties sortConfig = new Properties();
sortConfig.load(this.getClass().getClassLoader().getResourceAsStream("sortConfig.properties"));
Any help would be appreciated
my .java classes and my properties file are on the src, inside the same package folder
It looks like you do not have the fully qualified path to your properties file. You can get to it in 2 ways:-
Using java.util.ResourceBundle:
ResourceBundle bundle
=ResourceBundle.getBundle("br.com.example.sortConfig");
//.properties is implied
or
Using ClassLoader.getResouceAsStream:
sortConfig.load(this.getClass().getClassLoader().getResourceAsStream("br/com/example/sortConfig.propertie"));
For a good tutorial on how to load properties files resources check out this link.
An alternative could be to use this.getClass().getResourceAsStream() which accepts relative pathnames (relative to the package your class is in, that is), so you could simply write
sortConfig.load(this.getClass().getResourceAsStream("sortConfig.properties"));
This is useful when you specifically want to rely on your class and properties file being in the same package. (So when you move one during a refactoring, you'll have to move the other too.)

Categories