I use this code snippet to obtain a file as an input stream. The file version.txt is packaged in my app's jar, in the upper-most folder.
InputStream resource = getClass().getClassLoader().getResourceAsStream("version.txt");
This works almost all of the time. But for one user, it's picking up another version.txt, that's not in my jar. How can I ensure that this loads the specific version.txt file that is in my jar?
When you say, "upper-most folder", you mean the default package? If that's the case, you would have to ensure your JAR is earlier on the classpath than whatever is contributing the other version.txt file as Java searches along the classpath until it finds the first match.
Since it's hard to ensure your JAR would always be first, you should really place the version.txt file in a non-default package, such as:
com.yourcompany.yourproject.version
And then you'd need to modify the code to locate it:
Stream resource = getClass().getClassLoader().getResourceAsStream("com/yourcompany/yourproject/version/version.txt");
Using the default package is an anti-pattern.
This is the danger inherent in putting things in the top-level package, you can pick up things you didn't really want to. This can be a benefit (like with log4j config, for example), but it's usually not what you want.
I strongly recommend putting your version.txt within your application's package structure, e.g. in com.myapp (or whatever your package name is), and then load it from there using
getClass().getClassLoader().getResourceAsStream("com/myapp/version.txt");
the code snippet will use the class loader that loaded this class to find the version.txt file.
if the file exists in the classpath used by the classloader in more than one place, it may return the wrong file (depending on the classpath order).
Related
Is it expected that resources in .jar files included via Jetty's WebAppContext.setExtraClasspath method would be loaded in preference to resources with the same name/path within the .war?
——
I’m in the process of moving some dependencies out of .war files and including them instead via WebAppContext’s setExtraClasspath method (http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html#using-extra-classpath-method)
While doing so, I ran into a problem where one of the .jar files now moved out contains an ehcache.xml file, which seems to be read in preference to the one within the .war when Thread.currentThread().getContextClassLoader().getResourceAsStream(“ehcache.xml”) is used.
Now that I know that to be the case, I guess it’s not a big inconvenience to me if I need to rename the file to be unique, but I guess I’m wondering…
Am I loading the resource incorrectly (and if so, how can I do it to the .war takes priority)?
Was it only luck that the .war version took precedence previously (when the .jar in question was packed within the .war)?
Is this an expected drawback of using setExtraClasspath that I just have to live with?
Did I miss some documentation somewhere which would have clarified this for me?
Thanks to Jan on the jetty-user's list...
AFAIK we don't do any special handling of the extra classpath. The order
of paths that are added to the URLClassLoader that is the webapp
classloader is:
extra classpath
WEB-INF/classes
WEB-INF/lib/*.jar
The webapp classloader getResource(String) method first looks in itself
before looking in the parent (to conform to servlet spec inverted
classloading requirements), however the looking is all delegated to the
URLClassLoader, so it is whatever ordering the jvm has implemented, which
according to GrepCode
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/misc/URLClassPath.java#URLClassPath.0urls
looks like the search order will be as above.
Sad for my case, but makes sense.
I have no idea as to where to include the .jar file of mysql-connector/j using tomcat8.0.33. One of the blogs have mentioned to include in $CATALINA_HOME/common/lib, but i am not able to find "common".
And also could anyone please tell me how to create context configuration file for tomcat.
In the $CATALINA_HOME/conf, examine the catalina.properties file. There are definitions for where it will look for .jar files.
You can make the directory $CATALINA_HOME/common/lib, but it also must be loaded in one of the loaders defined in that .properties file. We actually make the common/lib, and modify the .properties, but there are differences of opinion on that approach.
You should also be aware of some differences in the loading because of the class loaders that are used by the different defined loaders.
I believe you are safe (in terms of it being found) in placing the MySQL library in the $catalina_base/lib directory, which I believe is included by default in the common.loader.
Copy it to $TOMCAT\lib folder.but that depends where to connection are to be managed.
I have a configuration file in xml format, that I need to load into my java code. While testing, I have imported it through it's absolute URL, but now I am about to compile and deploy the project as a jar, and that won't work anymore.
From previous experience, I think the right way to do this, is to use the ClassLoader, but I'm having some difficulties. Maybe because of my project setup, I do not know. I think I would be able to make this work, as I ahve done in the past, but I really want to make sure I do it the standard, conventional and/or correct way, so that I do not need to experiment every single time this comes up.
Here is the code I've tried to implement: http://www.mkyong.com/java/java-read-a-file-from-resources-folder/
However, this code:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
I could not use, due to needing the file in a static method of an abstract class. Therefor I switched it out with the following code:
ClassLoader classLoader = XmlConfigLoader.class.getClassLoader();
File file = new File(classLoader.getResource("configuration.xml").getFile());
The XmlConfigLoader is the containing Class. "configuration.xml" is located in the src/main/resources-folder, just as "file/test.xml" is in the example
I've run the code in debug-mode, and found that the file has the wrong path. Instead of looking in src/main/resources, it points to target/classes
Is there a setting option for default resource folder that I need to set?
Is src/main/resources the conventional place to store files like this?
Is my way of loading the ClassLoader correct in this setting?
As an additional info, this is a Maven project.
UPDATE:
My Current code actually works perfectly, apart from a single bug. The file is automatically transferred to the target/classes folder at compile time. However, whitespaces in the url are replaced by %20, and I have to manually change them back in order to make the system find the file. I am sure there is a better solution to this. Anyone?
It makes sense that the file has the path "target/classes", as this is the Class-Path in your jar's manifest file. If you want to get it to look somewhere else, edit the manifest file and append the resource classpath to it.
There are more details on how to alter your jar's classpath over at Setting classpath for a JAR
As you are using maven, the easiest thing to do is to put you resource file into the src/main/resources/META-INF directory, and maven will sort it out for you. See http://maven.apache.org/guides/getting-started/index.html#How_do_I_add_resources_to_my_JAR
I need to get the file names of each file that is in a particular folder inside my program's JAR while it is running. Is it possible to do this? I'm not sure where to start.
It needs to be done programmatically and be platform independent.
To list the contents of a jar file, simply run:
$jar tf MyJar.jar
Are you looking to do this programmatically from within java?
To do it programmatically, see this example.
You are asking for something that isn't available in general. Classes are loaded via ClassLoader instances, which may get class bytecode from many different places (network, jar file, .class files in a directory, dynamically generated).
The most you can know is the package hierarchy, which you can get from
myObject.getClass().getClassLoader().getPackages()
which returns a list of packages available at the point of invocation. For a given package you probably won't be able to tell where it came from.
I'm trying to get JDBC up and running in the Windows environment. What does it mean to include a .jar file in the classpath? I see how to modify the CLASSPATH environment variable for Windows... But what files need to go where and what does the CLASSPATH environment variable need to be set to? I've tried just about every combination that I can immediately think of, and I'm at a loss.
Thanks.
The CLASSPATH variable contains a list of directories where class files are found. A .jar file is really a zipped up directory, so the name of the .jar file itself should be in the CLASSPATH, not the name of the directory it is in.
If, for example, you had two directories with class file trees in them C:\java\classes\ and C:\java\specialclasses\ and two jar files C:\java\jars\jam.jar and C:\java\jars\jelly.jar then your class path variable would be set to C:\java\classes\;C:\java\specialclasses\;C:\java\jars\jam.jar;C:\java\jars\jelly.jar
As a general rule, unless you have two packages with classes with the same name (which hopefully you don't), then you just want to add things that are going to commonly be used to the CLASSPATH variable and not remove or replace things which are already there. By default, it includes the directories of the java.* classes, which are kind of important to include. Also, depending on your environment, other commonly used classes may have been added by an administrator.
Look no further than Oracle's own documentation
For instance, if you had 3 jars in /a/directory, you would do something like:
java -classpath /a/directory/jar1.jar;/a/directory/jar2.jar;/a/directory/jar3.jar
You would set the CLASSPATH variable in a similar fashion.