Locate resource using classloader or File? - java

I'm reading someone elses code; they have a line like so:
InputStream is = getClass().getResourceAsStream("../../../../../../file.txt");
Why would you do this instead of using File? Isn't the point of using the classloader to locate resources on the said classloaders classpath?

getResourceAsStream() allows you get access to files inside the JAR-container.

Related

Jar is not loading resources file

I have a project with a folder "src/main/resources" where inside there is the hibernate configuration file, I load it using this line of code
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
From inside the IDE it is working well, but when I create the jar it doesn't file the file.
How can I load it properly in the jar file too?
Thanks
Could you please try this:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("fileName").getFile());
I cannot say for ceratin that this is the issue without knowing how exactly you use the path extracted by:
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
but I can tell you this:
Run from an IDE the above line of code will return:
/path/to/project/src/main/resources/hibernate.cgf.xml
which is a valid filesystem path. You can then use this path to, for example, create an instance of File class and then use that instance to read the file contents.
However the same line of code run from inside a jar file will return:
file:/path/to/jar/jar_name.jar!/hibernate.cgf.xml
which is not a valid filesystem path. If you create an instance of File class using this path and then try to read the contents of the file you'll get an exception: java.io.FileNotFoundExeption
To read the contents of the file from inside of a jar you should use method Class.getResourceAsStream(String), which will return an instance of class sun.net.www.protocol.jar.JarURLConnection.JarURLInputStream (or equivalent in non-Oracle or non-OpenJDK Java). You can then use this object to read the contents of the file. For example:
InputStream inputStream = HibernateUtil.class.getResourceAsStream("/hibernate.cgf.xml");
Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
String fileContents = scanner.hasNext() ? sscanner.next() : "";
Most likely, the file is absent from the jar you create. There's too little information in your question, but I will try a guess:
Your hibernate.cgf.xml resides in the same directory as the Java sourcefles, and you are using a build tool (be it IDE, maven, gradle or an ant script) that expects resources to be stored in a separate directory.
It's easy to check: try to unzip your jar and see if the file is there (use any tool, you can just change the extension from .jar to .zip). I think you will see the file is absent.
Then come back with a question: "how to pack my non-java resources into a jar, using XXX", where XXX will be the name of the techology you are using for building the jar.
Most probably the slash in "/hibernate.cgf.xml" is not needed, if the hibernate.cgf.xml is in the same package as you class HibernateUtil.
You can access the file actually also via the classloader using the full path. Yet you never add to it the first slash.
Here is some code demonstrating how you can access the file using different methods:
public static void main(String[] args) {
// Accessing via class
System.out.println(SimpleTests.class.getResource("hibernate.cgf.xml").getPath());
// Accessing via classloader from the current thread
String path = Thread.currentThread().getContextClassLoader()
.getResource("simple/hibernate.cgf.xml").getPath();
System.out.println(path);
// Accessing via classloader used by the current class
System.out.println(SimpleTests.class.getClassLoader().getResource("simple/hibernate.cgf.xml").getPath());
}
In the example above the package 'simple' should be replaced by the package where your hibernate.cgf.xml is. But you should never have the slash at the beginning of the package declaration.

Reading xml file outside jar in java

I need to read an xml file which is outside the jar.I don't want to use relative path. It's an absolute path on unix box. As far as I understand, I guess there are 2 ways:-
1) Change the manifest file of jar and add that location in the classpath. In this case can I use getResource()?
2) Hardcode the path in getResourceAsStream(). My path is going to be something like this "/usr/local/folder1/folder2/".I read that I can't use getResource() for anything outside classpath and I need to use getResourceAsStream().
Which of these ways is a better approach?
Yes, both getResourceAsStream and getResource are dependent on the paths visible to the class loader that loads your class or the bootstrap class. If you want to use absolute paths, just use FileInputStream.
InputStream inputStream = new FileInputStream("/usr/local/folder1/folder2/myxml.xml");

how to find a local resource from dependent jar?

I have written a code that is packed to 1.jar
with this code:
return isProd? "/etc/waze/automation/devices.json":
DeviceRepositoryFromJsonFile.class.getClassLoader().getResource("devices.json").getPath().toString();
devices.json is here:
I have another project that depends on 1.jar
however the classLoader doesn't find the local devices.json file but rather one packed in the jar
anyhow it shows the file doesn't exist.
How can I fix this? just use a absolute path anyhow?
If as in your screenshot the devices.json locate in the src/main/resources and the package have successfully treat that as the package path and put in the jar file root directory, then you can just find the file via:
DeviceRepositoryFromJsonFile.class.getResource("/devices.json");
Note the "/" slash is important to indicate that to search from the root of the classpath.
It does not answer your question directly, but it may solve your problems faster.
As far as I can see you try to detect the absolute path to json file and pass it to another method so this file could be processed. Instead, it could be done simpler:
public byte[] getDevicesJsonBytes() {
return isProd
? IOUtils.toByteArray(ABSOLUTE_PATH_TO_PROD_FILE)
: IOUtils.toByteArray(DeviceRepositoryFromJsonFile.class.getResourceAsStream(RESOURCE_CLASSPATH);
}
The common way to read classpath resources it to use getResourceAsStream on class or classLoader instance. Also, many frameworks have their own resources abstractions, but I guess you don't need them now.

Loading files in JAR in Tomcat using getResourceAsStream

Is there a way to load files stored inside JARs using getResourceAsStream from Tomcat applications?
I have a library that puts all the files it needs inside its jar, along with the compiled classes. This code works when the library is used in standalone applications but not when the library is used inside Tomcat (using the PHP java-bridge).
final InputStream stream = Object.class.getResourceAsStream("/styles/foo.xsl");
I tried without success to use the solution outlined in question getResourceAsStream not loading resource in webapp and changed the code to
final ClassLoader resourceLoader = Thread.currentThread().getContextClassLoader();
final InputStream stream = resourceLoader.getResourceAsStream("/styles/foo.xsl");
The latter code does not work neither when the library is used standalone or when the library is used in Tomcat. In both cases stream == null.
The file I am trying to load is correctly stored on the JAR in /styles/foo.xsl. The JAR with all the classes and these other files is tomcat/webapps/iJavaBridge/WEB-INF/lib/.
Can someone suggest a piece of code that works both in Tomcat and non-Tomcat applications?
You need to remove the leading slash from the path. That would only work with classloaders which do not operate on the classpath root.
final ClassLoader resourceLoader = Thread.currentThread().getContextClassLoader();
final InputStream stream = resourceLoader.getResourceAsStream("styles/foo.xsl");
if you got a class file in the jar with the xsl try the following:
final ClassLoader resourceLoader = com.mypackage.MyClassInJar.class.getClassloader();
final InputStream stream = resourceLoader.getResourceAsStream("/styles/foo.xsl");
if there is no class, just create a dummy class.
i think that should work because you will always get the classloader responsible for the jar.

Java FileNotFoundException when running a jar file

In my project I load my resource using
getClass().getResource("/package/my_reource.file").getFile()
All works good when I run the project in netbeans, but if I run the jar file, I get FileNotFoundException, why?
Thanks.
You can use InputStream rather than getClass().getResource("/package/my_reource.file").getFile()
You should use
getClass.getResourceAsStream("/package/myresource.file")
I don't think you need the filename. You rather need its content. So use getResourceAsStream() to obtain the InputStream and read the content from there.
Check your jar. I believe that your file is not there.
The reasons depend on how are you creating your jar. If you are doing it using netbeans, check your settings. Probably it includes only *.class files? The same is about ant. Check tag.
The getFile() returns the file path portion of the URL returned by getResource()
So if its in the Jar, you have to read the jar to gett he file. If its on the filesystem you can read using FileInputStream.
If you want to get the InputStream and you don't create where you get it from use getResourceAsStream()

Categories