In one of my ongoing application I want to load java class file to the application when it runs. This particular java file is generated by the user and I don't know the name of that file. but I know the structure of that file (methods, variables , etc.) and location of that file. I know how to load java file using ClassLoader but for this instance it doesn't useful since I don't know the file name. so how do I load java file to my application and access it's method (These user generated java files are stored in one folder so it is ok to load all the java files at once)
Thanks!
Use an URLClassLoader.
If you know the directory the file is in, you can search it to find the class and use the ClassLoader to load it.
It appears you need to create your own ClassLoader.
Try reading this:
http://onjava.com/pub/a/onjava/2005/01/26/classloading.html
http://www.ibm.com/developerworks/java/library/j-dyn0429/
Related
I have a library which is used by a program. This library loads a special directory in the resources folder.
in the library I have the method
public class DataRegistry{
public static File getSpecialDirectory(){
String resourceName = Thread.currentThread().getContextClassLoader().getResource("data").getFile().replace("%20", " ");
File file = new File(resourceName);
return file;
}
}
in my program I have the main method
public static void main(String args[]){
System.out.println(Data.getSpecialDirectory());
}
When I execute the getSpecialDirectory() in a junit test within the data program, the resource is fetched and all is well.
When I execute the getSpecialDirectory() in the main method outside the data program (imported jar) I get the jars data directory and not the directory the program executing the thread is expecting.
I figured getting the parent class loader would have solved this issue... I believe I may have a fundamental issue in my understanding here.
For clarity:
(library)
Line 15 of this file: https://gist.github.com/AnthonyClink/11275442
(Usage)
Line 31 of this file:
https://gist.github.com/AnthonyClink/11275661
My poms may have something to do with it, so sharing them is probably important:\
(Library)
https://github.com/Clinkworks/Neptical/blob/master/pom.xml
(Usage)
https://github.com/Clinkworks/Neptical-Maven-Plugin/blob/master/pom.xml
Maven uses the target/classes and target/test-classes directories to compose the classpath used to run unit tests. The content of your src/main/resources and src/test/resources gets copied to these locations together with the compiled java sources (the .class files).
java.lang.ClassLoader.getResource returns a java.net.URL.
In the unit test situation, ClassLoader.getResource returns a file:// schemed URL, and your code works as expected.
When your code is executed when packaged in a jar file, ClassLoader.getResource no longer returns a file:// schemed URL. It can't because the resource is no longer a separate entity in a file system - it's buried inside the jar file. What you actually get is a jar:file:// schemed URL.
jar: URLs cannot be accessed through a [java.io.File] object.
If you only need to read the content of the resource you should use java.lang.ClassLoader.getResourceAsStream(...) and read the content from that.
Note that it is not possible to update the content of class loader resources.
Do you want the directory where the Java program was loaded from ? Can try
File f = new File(".").getCanconicalFile();
Or if you want all the places could try parsing the classpath from System.env or use the default class loader
If you want a directory relative to the jar from where your classes were loaded: Quoting from http://www.nakov.com/blog/2008/06/11/finding-the-directory-where-your-java-class-file-is-loaded-from/
URL classesRootDir = getClass().getProtectionDomain().getCodeSource().getLocation();
The above returns the base directory used when loading your .class
files. It does not contain the package. It contains the classpath
directory only. For example, in a console application the above
returns someting like this:
file:/C:/Documents%20and%20Settings/Administrator/workspace/TestPrj/bin/
In a Web application it returns someting like this:
file:/C:/Tomcat/webapps/MyApp/WEB-INF/classes/
FYI This might apply if the user id running program cannot read all folders: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getProtectionDomain%28%29
or pass a .class object of the calling class as a parameter and get its classloader
There is no guarantee that you have a directory for your resources as far as I know. Java provide methods to get a resource as a InputStream, but nothing that can easily get the File for a resource, although it is possible to get the URL for a given resource.
If you need a special working directory in your application, I recommend having that passed as a system property, a program parameter, a web application parameter, or something else that lets you know where your application files are. You can even populate this directory with a ZIP file that you include as a resource in your application, as the ZIP libraries in Java do accept input streams as parameters.
While user #tgkprog is right and his answer correct, I can hardly imagine that you really want what you seem to have asked for and what he correctly answered in (3). Please edit your question and explain
what the output should look like if resourceName would be printed to the console,
if you really want the JAR file's location (in my test case that would be something like file:/C:/Users/Alexander/.m2/repository/com/clinkworks/neptical/0.0.1-SNAPSHOT/data, which does not make sense because you do not want to read from or even write to the local Maven cache),
or if you maybe rather want to read a resource directly from the JAR file or any other location such as the current working directory etc.
Otherwise I am afraid there is no good way to answer the question.
I'm trying to find a txt file in a separate folder to the class
Class file
C://workspace/project/src/pkg/Class.java
txt file
C://workspace/project/doc/pkg/myFile.txt
I'm trying to find the text file without having to hard code the C://workspace/project/ bit
Is this possible?
Currently I can use a classpath:/pkg/myFile.txt when the file is in the same package as Class.java using a resource loader
You could inclide the doc folder as a source folder. That way you can keep your resources separate from the code, but still have access to it using a classloader.
Of course that will only work for you when your resource can be part of the jar. If not, you may want to consider using a properties where you can configure the complete path to the resource.
Try getClass().getResource() or getClass().getClassLoader().getResource() if it is in the same jar-file
I'm trying to use a binary resource in my application. I need it for crypt/decript passwords. The file is located in the "classes" folder of my ear, just like properties files that the application access without problems.
Anyway, I am loading the files as follows.
ClassLoader.class.getResourceAsStrem(/file.xxxx);
But in the case of the binary file the resultant InputStream is null.
The question is, why it works with properties files and does not with a binary file? What can i do for load a binary resource?
Best regards.
Ensure that the file is available on the class path.
Use the context class loader instead - this will ensure that the code trying to look up the file can reside in a shared library as well.
Something on the lines of:
Thread.currentThread().getContextClassLoader().getResourceAsStream(..)
Hope that helps.
Instead of ClassLoader use the class name where you are currently in.
YourClass.class.getResourceAsStrem(/file.xxxx);
How can I find path of a xml (static myXml.xml) file that is embedded into jar? Obviously not by absolute path but I am facing same kind of problem with relative paths. I cannot get it relative to home folder as Java returns different home folder depending upon from where I am calling the accessing Java class. For instance, from:
command prompt
App server
Eclipse launcher
Eclipse remote debugger etc
Is there someway that my accessing class (packed in same jar) may access embedded xml regardless of where jar file exists and who is trying to access it?
What you need to do is use the class loader to load the file:
InputStream stream = this.getClass().getClassLoader().
getResourceAsStream("myXml.xml");
The above code assumes that the file is at the top level of your jar.
Have you tried the getResource and getResourceAsStream methods in the Class class? Usually those are what I have to resort to in these situations.
Hope this helps.
You can use ClassLoader#getResource(..) to get InputStream of a file from the classpath:
Object.class.getClassLoader().getResource().openStream()
Also there are some other methods in ClassLoader which could be useful in your case.
I want to create an ini file to store some settings for my application. Is it a good idea to find where the jar file is located and create an ini file there? If yes, then how can I find the location of the jar file?
But if you know a better solution for something like this, I would like to hear some of them.
EDIT: I'm using mac and I want to run the same application in windows. I could write something in the System.getProperty("user.home") directory, but I want to keep the system clean, if the user decides to remove the app. There is no a better way to store the settings file, for example in the same directory with the application?
You can locate your application directory using the ClassLoader. See: Java: finding the application directory. Rather than an .INI file, use a .properties file - you can load and save this via the Properties class.
As others have noted, you should not write user settings to your application directory. What if the user does not have write access to the application directory? What if your application is being used by multiple users on the same system at the same time? Neither of these situations are unusual, even on Windows.
You might still want to load some settings from the application directory - perhaps the administrator has configured default settings there.
A common convention is to save user settings to the user's home directory:
/home/user/.eclipse
C:\Documents and Settings\User\.eclipse
Although this means you might leave stray files behind, this can be beneficial if the user re-installs the app. Document such things in a README. Here is how to create and get a reference to the directory:
public static File getSettingsDirectory() {
String userHome = System.getProperty("user.home");
if(userHome == null) {
throw new IllegalStateException("user.home==null");
}
File home = new File(userHome);
File settingsDirectory = new File(home, ".myappdir");
if(!settingsDirectory.exists()) {
if(!settingsDirectory.mkdir()) {
throw new IllegalStateException(settingsDirectory.toString());
}
}
return settingsDirectory;
}
On unix-like operating systems, starting the directory name with a period (".myappdir") will make the directory hidden. On Windows, it will be located below My Documents, so users will not see the directory unless they go looking for it.
If the settings are only written by your application (rather than edited manually), consider using the Preferences API.
You should not be storing temp files in the install directory of an application. Remember, the user running the application may not have write access to that directory. The safest place to put stuff like that is in C:\Documents and Settings\username\Application Data\ApplicationName folder (adjusting the name as necessary).
That said, however, I would probably store that type of stuff in the registry instead of a file on their computer. (But, that's just me.)
Typically Java programmers don't use .ini files, but .properties files (different format). You can use the java.lang.Properties class as a nice programmatic wrapper if you do.
While you can get the location of your jar file by calling getProtectionDomain().getCodeSource().getLocation() on your class's .class member, I do not recommend that you do this.
I would instead write the file to the System.getProperty("user.home") directory - the users' home directory, or if it is truly temporary, System.getProperty("java.io.tmpdir")
It depends whether your ini needs to be human readable/writable under normal circumstances. If not, you can use a properties file rather than an ini file, and store it in the "user" directory.
As for finding the jar file, you would have to find the ClassLoader for a class known to be loaded from the jar, check that it was the appropriate type of ClassLoader (ie that it's really been loaded from a jar), and you can extract the path from that. I can probably dig out the code to do this if that's really what you want. I wouldn't necessarily recommend it.
EDIT The user.home property will give you the user directory, which you can safely use.
The idea with the .properties file instead of the INI file is good. Also, if you store some sensitive data in there, you may consider encrypting it. Check this out:
https://www.owasp.org/index.php/How_to_encrypt_a_properties_file
or this:
encrypt and decrypt property file value in java