Jar is not loading resources file - java

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.

Related

Using getResourceAsStream is not working in Java [duplicate]

This question already has answers here:
How to read text file from classpath in Java?
(17 answers)
Closed 7 years ago.
I have a very simple method which uses the getclass().getResourceAsStream() method to read a file. However it always returns null and I can't figure out what is wrong. Here is my piece of code.
InputStream sw = getClass().getResourceAsStream("/filename.txt");
BufferedReader bf = new BufferedReader( new InputStreamReader(sw));
sw always remain null. the file filename.txt exist in the root directory of my project.
EDIT:
I found the reason. I realized that I was running my project from Eclipse and the project was not part of the classpath on my PC. However if I package my program as a jar file and then run it, the files in the jar file are considered as resources and can be read using the getResourceAsStream() method.
The method Class.getResourceAsStream() looks for the designated resource within the Java class path, not based on the project root.
The project root usually is not part of the classpath. Instead, you should have a src folder (or a similar name), which contains the Java files and may also contain your text file. Or, if you use Maven, you have folders src/main/java and src/main/resources, which are classpath roots. In this case, the text file should reside in the resources folder.
If your project gets packaged into a .jar file, all its resources are packaged in the .jar file along with the .class files, and will be found by Class.getResourceAsStream().
Root of your project is not always the root of the path from the ClassLoader point of view.
Easiest way to find out where it is trying to load the resource from:
System.out.println(MyClass.class.getResource("/").getPath());
And after that you may be able to easily find out the part of the project or run configuration that causes the difference between your assumption and the reality about the right placement of the file.
getResourceAsStream() reads a resource file, ie a file into .jar file (or resource directory), not a regular file in working directory on disk. Use FileReader to read a file from disk
user likewise,
InputStream sw = this.class.getClassLoader().getResourceAsStream("filename.txt");
Note : filename.txt file should be present on classpath.
Just to be complete, here's a simple test that does print out the absolute path of a resource. You can use this inside any class to find the location of that class on your hard drive, in case it isn't obvious what your build system is doing. Just substitute the name ErrorTest for the class you are checking.
public class ErrorTest
{
public static void main(String[] args )
{
final String className = ErrorTest.class.getSimpleName().replace( '.', '/').concat(".class");
System.out.println(ErrorTest.class.getResource(className).getPath() );
}
}
Output of this program:
run:
/C:/Users/Brenden/Google%20Drive/proj/tempj8/build/classes/quicktest/ErrorTest.class
BUILD SUCCESSFUL (total time: 0 seconds)

java.io.FileNotFoundException: the system cannot find the file specified

I have a file named "word.txt".
It is in the same directory as my java file.
But when I try to access it in the following code this file not found error occurs:
Exception in thread "main" java.io.FileNotFoundException: word.txt
(The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.util.Scanner.<init>(Unknown Source)
at Hangman1.main(Hangman1.java:6)
Here's my code:
import java.io.File;
import java.util.*;
public class Hangman1 {
public static void main(String[] args) throws Exception {
Scanner input = new Scanner(new File("word.txt"));
String in = "";
in = input.nextLine();
}
}
Put the word.txt directly as a child of the project root folder and a peer of src
Project_Root
src
word.txt
Disclaimer: I'd like to explain why this works for this particular case and why it may not work for others.
Why it works:
When you use File or any of the other FileXxx variants, you are looking for a file on the file system relative to the "working directory". The working directory, can be described as this:
When you run from the command line
C:\EclipseWorkspace\ProjectRoot\bin > java com.mypackage.Hangman1
the working directory is C:\EclipseWorkspace\ProjectRoot\bin. With your IDE (at least all the ones I've worked with), the working directory is the ProjectRoot. So when the file is in the ProjectRoot, then using just the file name as the relative path is valid, because it is at the root of the working directory.
Similarly, if this was your project structure ProjectRoot\src\word.txt, then the path "src/word.txt" would be valid.
Why it May not Work
For one, the working directory could always change. For instance, running the code from the command line like in the example above, the working directory is the bin. So in this case it will fail, as there is not bin\word.txt
Secondly, if you were to export this project into a jar, and the file was configured to be included in the jar, it would also fail, as the path will no longer be valid either.
That being said, you need to determine if the file is to be an embedded-resource (or just "resource" - terms which sometimes I'll use interchangeably). If so, then you will want to build the file into the classpath, and access it via an URL. First thing you would need to do (in this particular) case is make sure that the file get built into the classpath. With the file in the project root, you must configure the build to include the file. But if you put the file in the src or in some directory below, then the default build should put it into the class path.
You can access classpath resource in a number of ways. You can make use of the Class class, which has getResourceXxx method, from which you use to obtain classpath resources.
For example, if you changed your project structure to ProjectRoot\src\resources\word.txt, you could use this:
InputStream is = Hangman1.class.getResourceAsStream("/resources/word.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
getResourceAsStream returns an InputStream, but obtains an URL under the hood. Alternatively, you could get an URL if that's what you need. getResource() will return an URL
For Maven users, where the directory structure is like src/main/resources, the contents of the resources folder is put at the root of the classpath. So if you have a file in there, then you would only use getResourceAsStream("/thefile.txt")
Relative paths can be used, but they can be tricky. The best solution is to know where your files are being saved, that is, print the folder:
import java.io.File;
import java.util.*;
public class Hangman1 {
public static void main(String[] args) throws Exception {
File myFile = new File("word.txt");
System.out.println("Attempting to read from file in: "+myFile.getCanonicalPath());
Scanner input = new Scanner(myFile);
String in = "";
in = input.nextLine();
}
}
This code should print the folder where it is looking for. Place the file there and you'll be good to go.
Your file should directly be under the project folder, and not inside any other sub-folder.
If the folder of your project is named for e.g. AProject, it should be in the same place as your src folder.
Aproject
src
word.txt
Try to create a file using the code, so you will get to know the path of the file where the system create
File test=new File("check.txt");
if (test.createNewFile()) {
System.out.println("File created: " + test.getName());
}
I was reading path from a properties file and didn't mention there was a space in the end.
Make sure you don't have one.
Make sure when you create a txt file you don't type in the name "name.txt", just type in "name". If you type "name.txt" Eclipse will see it as "name.txt.txt". This solved it for me. Also save the file in the src folder, not the folder were the .java resides, one folder up.
I have the same problem, but you know why? because I didn't put .txt in the end of my File and so it was File not a textFile, you shoud do just two things:
Put your Text File in the Root Directory (e.x if you have a project called HelloWorld, just right-click on the HelloWorld file in the package Directory and create File
Save as that File with any name that you want but with a .txt in the end of that
I guess your problem is solved, but I write it to other peoples know that.
Thanks.
i think it always boils to the classpath. having said that if you run from the same folder where your .class is then change Scanner input = new Scanner(new File("word.txt")); to Scanner input = new Scanner(new File("./word.txt")); that should work

Not able to read file from jar in tomcat

I have a web application running under tomcat 7, and in one of the class, Im trying to read a file in one of the jar under WEB-INF/lib folder.
URL resourceURL = MyClass.class.getClassLoader().getResource("xml/xslt/master.xsl");
File xslfile = new File(resourceURL.getPath());
AssertUtil.assertTrue(xslfile.exists(),"xsl file not found");
Both MyClass and master.xsl resides in the same jar and there is no issue with packaging. But above snippet fails in the assertion statement as xslfile.exists returns false. The URL correctly resolves to the location of the file inside the jar as given below
file:/<MY_WEBAPP_LOCATION>/MyApp/WEB-INF/lib/MyComponent.jar!/xml/xslt/master.xsl
where MY_WEBAPP_LOCATION corresponds to the absolute path to my tomcat servers webapp directory.
But if I rewrite the code as below to read as inputstream, it works fine.
InputStream xslFile = MyClass.class.getClassLoader().getResourceAsStream("xml/xslt/master.xsl");
Can anyone explain what is preventing the creation of File from the jar resource, whereas the inputstream creation is working perfectly fine. Is there any additional permission settings needed from tomcat side, to read a file inside jar ?
EDIT: One more observation, if the file is placed under WEB-INF/classes, creation of File with above code works fine. Issue is only when it is placed in a jar under WEB-INF/lib
Be careful it seems that ClassLoader.getResource does not handle relative path.
See this.
GetResourceAsStream happens to take the path relative to the ClassLoader (and not the class !!). I think you're lucky enough that there are the same here.
If it is a Desktop application getResource() will work
But as this is a web application the resource needs to be extracted from Context , hence getResoruceAsStream()
It is not a permission problem, but the use of java.io.File API - in particular constructor http://docs.oracle.com/javase/7/docs/api/java/io/File.html#File%28java.lang.String%29
When you are constructing File object using
File xslfile = new File(resourceURL.getPath());
you are using java.io.File#File(String) method which expects an "abstract pathname". What is an acceptable/valid pathname is described by javadoc of the File class: http://docs.oracle.com/javase/7/docs/api/java/io/File.html
String value that your are getting from getPath() method:
file:/<MY_WEBAPP_LOCATION>/MyApp/WEB-INF/lib/MyComponent.jar!/xml/xslt/master.xsl
simply does not constitute a valid "abstract pathname" - it is a URL that is converted to a java.lang.String (and IMHO should be returned with URL scheme of "jar" and not "file"). Therefore a call to
isExist()
returns false as there is no file with such name on your disk.
On the other hand if the resource is outside of a jar (e.g. under WEB-INF/classes directory) resourceURL.getPath() will return a value that presents a valid abstract pathname as the resource in question is indeed a simple file.
When you use java.lang.ClassLoader#getResourceAsStream(java.lang.String) the method streams out the resource directly into a java.lang.InputStream and might not even use File class in its implementation.

Open file; try filesystem first, then JARs

I'm trying to have my application load a resource (binary file) transparently:
If the file exists under the current directory, open it.
If not, try looking in the current JAR file if applicable.
If not, try looking in other JAR files. (This is optional and I don't mind explicitly specifying which JAR files.)
So far I know of File which opens a local file and ClassLoader which has getResource* for JAR contents.
Is there a class which combines the two? If not, how should I go about writing it myself? Should I write a ClassLoader which also checks the local filesystem? Using File? (I'm very unfamiliar with Java and don't even know what's a good type to return. InputStream?)
Thanks
P.S. By "file" I mean "path", e.g. "data/texture1.png".
Doing #1 and #3 is pretty easy. Doing #2 (just looking in the current JAR only) is much harder as it requires you figuring out what JAR you
If you wanted to check the filesystem first, otherwise load from classpath, it would be something like:
public java.io.InputStream loadByName(String name) {
java.io.File f = new java.io.File(name);
if (f.isFile()) {
return new FileInputStream(f);
} else {
return getClass().getResource(name);
}
}
If you want to prefer loading from the same JAR file first, you will need to figure out where it is. Check out Determine which JAR file a class is from for more info on figuring out the JAR file you want to load the resource from.
A URLClassLoader should be able to load both and try the file path first if the file path is on the class path ahead of the jar.
Regarding your comments:
I know that relative jar URLs don't
work. That's why the Spring guys came
up with the Resource abstraction.
Read about it here.
You might want to check the answers
to this Question: Loading a file
relative to the executing jar
file. The problem is similar to
yours.
Current jar file and current directory are not concepts in the JVM like they are when you're running a shell script. You would need to specify a directory to be used for loading the files that you're interested in, such as with a system property while executing the JVM:
java -Ddirectory.to.scan=/home/aib
Then retrieve this property:
String dir = System.getProperty("directory.to.scan");
Now when talking about JAR files, all JAR files specified explicitly on the classpath when you start the JVM are loaded by the ClassLoader. You can get the ClassLoader of a specific class by:
InputStream is = <Your class>.class.getClassLoader().getResourceAsStream("binary file");
Note that any jar file loaded by the current class loader is searched.

How do I reference a resource in Java?

I need to read a file in my code. It physically resides here:
C:\eclipseWorkspace\ProjectA\src\com\company\somePackage\MyFile.txt
I've put it in a source package so that when I create a runnable jar file (Export->Runnable JAR file) it gets included in the jar. Originally I had it in the project root (and also tried a normal sub folder), but the export wasn't including it in the jar.
If in my code I do:
File myFile = new File("com\\company\\somePackage\\MyFile.txt");
the jar file correctly locates the file, but running locally (Run As->Java Main application) throws a file not found exception because it expects it to be:
File myFile = new File("src\\com\\company\\somePackage\\MyFile.txt");
But this fails in my jar file. So my question is, how do I make this concept work for both running locally and in my jar file?
Use ClassLoader.getResourceAsStream or Class.getResourceAsStream. The main difference between the two is that the ClassLoader version always uses an "absolute" path (within the jar file or whatever) whereas the Class version is relative to the class itself, unless you prefix the path with /.
So if you have a class com.company.somePackage.SomeClass and com.company.other.AnyClass (within the same classloader as the resource) you could use:
SomeClass.class.getResourceAsStream("MyFile.txt")
or
AnyClass.class.getClassLoader()
.getResourceAsStream("com/company/somePackage/MyFile.txt");
or
AnyClass.class.getResourceAsStream("/com/company/somePackage/MyFile.txt");
If I have placed i file in a jar file, it only worked if and only if I used
...getResourceAsStream("com/company/somePackage/MyFile.txt")
If I used a File object it never worked. I got also the FileNotFound exception. Now, I stay with the InputStream object.

Categories