so I am in the process of making a small application.
Right now, the project works fine. I am running it through an IDE. The problem comes about when trying to run the project as a jar - which is the end result. Right now, it fails to properly load the required files (classes and simple ASCII files).
The method I am using is one based off of:
final Enumeration<URL> paths = CLASS_LOADER.getResources("");
Where CLASS_LOADER is an instance of class.getClassLoader().
This works great when not inside a jar. Inside a jar though, it seems to fail horribly. For example, in the code above, paths would be empty.
I am assuming that the fault is that the files are all within a jar - the same jar to be precise.
The class path for the manifest file is blank at the moment.
If it helps, I have two tasks that require loading files.
I need to create a list of all files that are a subclass of
another class.
I need to load a list of language files (all of
which are in the same directory).
If you need anything else to help debug this problem or provide a solution - let me know. Thanks for reading this!
For ClassLoader.getResources() to work you need to feed a path relative to the jar root. If you want to search the jar then ClassLoader public API won't help you. You have to use custom code based on java.util.jar.JarFile, like the one here.
Related
I'm working with a local WebSphere server configured in IntelliJ Idea, and the application I'm working on is using a third-party library that loads a properties file with:
ThirdPartyClass.class.getClassLoader().getResourceAsStream(fileNameParameter);
It uses the default bootstrapClassLoader.
I've been instructed to make sure the properties file is in a config directory so that it can be edited without deploying a code change. My project looks something like this:
ProjectName
Configs
my.properties
src
java (sources root)
packages, .java files, etc
main (resources root)
schemas, web docs, etc
I have tried several of paths to make it work but it always returns null. Since I initially thought it was reaching from within the third party library package, I tried adding several ..\'s to the file path, but then I learned that this method loads from the classpath, so I pulled a
String test = System.getProperty("java.class.path");
and upon inspection, my classpath is all made up of websphere directories and jars within them:
C:\Users\me\Programs\IBM\AppServer\profiles\AppSrv01/properties
C:\Users\me\Programs\IBM\AppServer\AppSrv01/properties
and several jar files in C:\Users\me\Programs\IBM\AppServer/lib/
So just as a test I stuck the file in C:\Users\me\Programs\IBM\AppServer\AppSrv01/properties, then tried to grab it with just its file name (my.properties), but still couldn't reach it. I've also tried moving the file into the src directory and the main directory, but no matter what I do it just can't seem to find the file.
I'm aware that this method is typically used to grab resources from within a jar file, but from my understanding it seems like it should be possible to reach my file from outside of one as long as it's in a directory in the classpath... but apparently not since that didn't work.
I have the absolute path on my hard drive and will have said path on the server; is there a way to derive the path that ClassLoader.getResourceFromStream() wants with that info? Failing that, is there some obvious mistake I'm making with the resource url?
I think your fileNameParameter simply needs to start with / to indicate that it is in the root level of the classpath. Otherwise it will be searched relative to the class it is loaded from, i.e. the package of ThirdPartyClass in your example.
In this previous question, I was trying to rework some Matlab code and figure out a package called javaplex to be compatible with Octave; it uses Java, but is tooled for Matlab, hence that issue. Now in an interval of time, I was busy/running simulations, and hadn't gotten around to a final step - actually using the package, with most all of the difficulties worked out. It turns out that another step exists: I need to convert an Octave array to a Java array (although I'm not sure why this issue didn't come up in Matlab).
To do so, I have turned to this script, in which the comments indicate that when using it, it
Assumes the JIDT [Java Information Dynamics Toolkit] jar is already on the java classpath - you will get a java classpath error if this is not the case.
So I go to the JIDT GitHub page and download this package. Now I am not a very avid user of java, so I believe I am failing to see something fairly straightforward: I am not sure where the "JIDT jar" is that is referenced in the above block quote! I can't find such a particular jar file to put in Octave's java classpath. In this tutorial for JIDT, they say you need the "infodynamics.jar" file in the classpath (page 9). I'm not sure what jar file I should be looking for, and where. Any help understanding the nature, name and location of this jar file (within the infodynamics toolkit folder) would be appreciated!
As an inevitable follow-up question, because this will come up upon resolving this issue, I would like to clarify the following procedure is how to add a jar file to the Octave (static) java classpath (following this answer here, I wasn't sure if I was implementing correctly):
I create a file called "javaclasspath.txt" inside of the directory I use in Octave.
I enter the name of files as follows: "./path/to/your-file.jar"
I suppose my main issue here is where do I start the path (all the way back with "C:/..."?), and do I put this "javaclasspath.txt" file in the directory folder I will be using most of the time in Octave?
Edit: I cannot find "infodynamics.jar" as shown here:
The JIDT jar is named infodynamics.jar and it is located in the root of the downloads infodynamics-dist-1.4.zip file.
We bought a solution from a provider a couple of years ago, droped the .jar file in the standard location in IFS /QIBM/UserData/Java400/ext/ and we have been working correclty ever since with this.
However a couple of months ago the provider released a new .jar with some new functions we would like to use. However they also changed the names of several classes and methods that we are using.
So what we were thinking of doing, if possible, is define a path on which the old programs when they need to use that .jar look for that .jar in the defined path. And for the new programs that we want to use the new .jar file we wanted to have different path for that.
At this point I don't know if this is possible to do. I have been searching everywhere for this information without luck. So if someone around here as some clue it would be fantastic.
Thank you for your time.
Edit: So I was reading through your advices and I have these coments.
I already asked the supplier for assistance but since this wasn't designed for AS400 they don't provide support.
I tested the possibility of the classpath. I deleted the files from the /QIBM/UserData/Java400/ext/ and put them in /QIBM/JARS/old/ then I created a CL that did this:
ADDENVVAR ENVVAR(CLASSPATH) VALUE('/QIBM/JARS/old') REPLACE(*YES)
After I first executed this new CL then I tried a program that would use the .jar that I had in the location /QIBM/JARS/old and I got the error of the class not found. So either I did something wrong or this isn't actually a solution.
HotLicks do you mean that it is not possible to have users A1 and B1, and A1 using /QIBM/JARS/old/A.jar and B1 using /QIBM/JARS/new/A.jar at the same time?
You can adjust the Java classpath.
You probably want to redefine your extensions classpath when running with the new version of the jar.
Create a new directory -- i.e. /QIBM/UserData/MyJava/ext
Copy the jars files you need from /QIBM/UserData/Java400/ext to /QIBM/UserData/MyJava/ext
Add your new jar file to /QIBM/UserData/MyJava/ext.
When starting the Java program, use the following define to set the extensions directory: -Djava.ext.dirs=/QIBM/UserData/MyJava400
Note: You may need to adjust the directory based on the current settings of java.ext.dirs. You can find the current settings by running the following from QSHELL.
echo '!callmethod java.lang.System.getProperty(java.ext.dirs)' | java -cp /qibm/proddata/http/public/jt400/lib/jt400.jar com.ibm.as400.access.jdbcClient.Main jdbc:db2:localhost
Call returned /QOpenSys/QIBM/ProdData/JavaVM/jdk50/32bit/jre/lib/ext:/QIBM/UserData/Java400/ext
In my case, I would then set -Djava.extdirs=/QOpenSys/QIBM/ProdData/JavaVM/jdk50/32bit/jre/lib/ext:/QIBM/UserData/MyJava/ext
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 am using one third party jar in my code. In the jar file , in one of the classes, when I opened the class using de-compiler, the code below is written:
java.net.URL fileURL = ClassLoader.getSystemResource("SOAPConfig.xml");
Now I am using this in my webapplication, where should I place this SOAPConfig.xml so that it will find the fileURL.
Note: I have tried putting this XML in WEB-INF/classes folder. But it is not working. Your help will be appreciated.
In Addition: In the explaination you have given, It is telling me not to use this code snippet inside the third party jar in this way...What is the exact usage of this statement
ClassLoader.getSystemResource will load the resource from the system classloader, which uses the classpath of the application as started from the command line. Any classloaders created by the application at runtime (i.e. the one that looks in WEB-INF/classes) are not on the system classpath.
You need to
Look through the script that starts your server, find out which directories are on the classpath there, and put your SOAPConfig.xml in one of those. If necessary, change the classpath in the script to look in a separate directory that's just used for your config file.
Track down the person who used ClassLoader.getSystemResource in the library, kick them squarely in the nuts, and tell them never to do that again.