Java: getCodeBase() on non-applet application - java

I'm trying to create a URL to access a local file like so:
URL myURL = new URL(getCodeBase(), "somefile.txt");
But it throws a NullPointerException when it attempts getCodeBase(). I'm fairly certain that the reason behind this is because the class file that this code belongs to is not an applet. Is there any way I can get the code base without using an applet? I just want to access a local file without having to put the actual directory in (because when others run the application the directory path will obviously not be the same).

I would use the following to be relative to the working directory
URL myURL = new URL("file:somefile.txt");
or
URL myURL = new URL("file", "", "somefile.txt");
or
File file = new File("somefile.txt");

You don't need to get the code base.
If the file resides on your classpath (this includes the path where your classes are deployed), you can access vía the ClassLoader method getSystemResource.
URL myURL = ClassLoader.getSystemResource("somefile.txt");

If somefile.txt is read-only, put it in a Jar that is on the run-time class-path of the application. Access it using:
URL urlToText = this.getClass().getResource("/path/to/somefile.txt");
If it is read/write:
Check a known sub-directory of user.home for the file.
If not there, put it there (extracting it from a Jar).
Read/write to the file with known path.

See How to create a folder in Java posting, which asked very similar question.
As Tomas Narros said above, the proper way to do this is to use the ClassLoader to locate resource files in the Classpath. The path you pass to the ClassLoader is relative to the classpath that was set when you started the Java app.
If you browse the above link, you'll see some sample code showing how to resolve the path to a file in your classpath.

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.

Path for retrieving resources with ClassLoader

Basically, I want to include my main JFrame's icon in the JAR file, so not to need to load it from an external location.
To achieve this, I searched about Java's resource system.
What I have done with Eclipse:
I have created a new folder named "res":
I have copied the files inside it using Windows' explorer:
I have made that folder a source folder:
I have written this code:
URL url = ClassLoader.getSystemResource("/res/icona20.ico");
But url is null.
What did I do wrong?
As mentioned you seem to have added res as source folder, so it is a root, not to name, like src.
URL url = ClassLoader.getSystemResource("icona20.ico");
Class loaders use an absolute (case-sensitive) path, without explicit leading slash /....
Relative paths with an obligatory leading slash for absolute paths:
URL url = Xyz.class.getResource("/icona20.ico");
And you might prefer .png instead of .ico as the latter format is not standard in Java SE.
(About common practices.) The build tool maven uses as nice standard the following source folders:
/src/main/java/
/src/main/resources/
/src/test/java/
/src/test/resources/
Your usage of res is reminiscent of MS Visual Studio ;).
The classloader will get the resources starting from each source folder you added to the classpath. Therefore, the URL should be the following:
URL url = ClassLoader.getSystemResource("icona20.ico");

Relative path of my Java server

I'm trying to create a file in my server. I have sent a image, and I want to create that Image in a folder of my server, but with relative path.
String filePath = "C:\\Users\\Administrador\\Desktop\\Proyecto\\clienteServidor\\Server\\folder\\image.jpg";
File imageFile = new File(filePath);
...
I'm doing with the absolute path.
Thanks
hard coding a directory is seldom good for coding. What happens if there is a typo in your code. Using a combination of ./ or ./*
or even using
new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
This is explained here.
It is doable but, as Dmitry said, it might not work on every server. SecurityManager class should be consulted if your webapp has the privilege to write to that folder. or you will get an exception.
One way to do it is via ServletContext:
URL webAppRoot = this.getServletConfig().getServletContext()
.getResource("/images/new-image.jpg");
This will point to your ${tomcat}/webapps/mywebapp/images/new-image.jpg.
Another way is via ProtectionDomain:
URL runningClassLocation = this.getClass().getProtectionDomain()
.getCodeSource().getLocation();
But this will most likely give you jar:file://...myapp.jar!/my/package/servlet.class.
After you have the URL you convert it to File and append any relative path to your image folder.
UPDATE:
I agree with Jim, and emphasize that doing it like this is just for academic purposes.
Java is not like PHP so you shouldn't have uploads folder inside your web application's folder. Usually this is done by enabling an administrator-level user to specify a file path to a folder reserved for your application's storage needs.

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.

How to get the path of a directory where my running jar file is?

I try to retrive a path of a directory where my executable jar file is situated.
That means: I have the following structure:
--> Application (this is a folder somewhere in my file system)
--> application.jar (this is my java application
--> SomeData (folder in the same directory like the application)
--> some other folders
......
When I start my application.jar via command line I want to parse some files inside the SomeData folder.
In https://stackoverflow.com/a/320595/1540630 they already showed how to get the current path of a running jar file but when I execute the statement:
System.out.println(XMLParser.class.getProtectionDomain().getCodeSource().getLocation().getPath());
...I just get the following:
/.../Application/application.jar
But I just want to have:
/.../Application/
Better to say in later steps I need
/.../Application/SomeData/SomeFolder/data.xml
Can someone help me please?
CodeSource.getLocation() gives you a URL, you can then create new URLs relative to that:
URL jarLocation = XMLParser.class.getProtectionDomain().getCodeSource().getLocation();
URL dataXML = new URL(jarLocation, "SomeData/SomeFolder/data.xml");
You can't simply do new File(...getCodeSource().getLocation().getPath()) as a URL path is not guaranteed to be a valid native file path on all platforms. You're much safer sticking with URLs and passing the URL directly to your XML parser if you can, but if you really need a java.io.File then you can use an idiom like this to create one from a URL.
Once you have the jar's location you can use
new File(new File(jarPath).getParent(), "SomeData/SomeFolder/data.xml");
Since you already have the path as a string. You can try the following
String path = XMLParser.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String parentFolder = new File(path).getParent();

Categories