For various historical reasons, I have an old java application which shares a local lib/ directory of library .JARs with some other applications. In this directory is a number of versioned copies of the same library, for example:
...
log4j-1.2.16.jar
log4j-1.2.17.jar
slf4j-api-1.7.5.jar
slf4j-api-1.7.21.jar
slf4j-log4j12-1.7.5.jar
slf4j-log4j12-1.7.9.jar
...
When my java app starts, how does it decide which .jar file to load? As far as I know, the CLASSPATH is just set to ./lib/. But it uses the Tanuki Service wrapper to start, so I'm not 100% sure of this.
I can't delete any of these existing .JARs, is there a way to specify exactly which .JARs my app will use ?
After this old application was patched, now I'm getting a NoClassDefFoundError, and I suspect the app is loading an older (or newer) version of a .JAR that conflicts with another library (BoneCP and slf4j).
Which jar first in classpath that is picked up when JVM classloader is looking for a class. So you can try to add those jars in different order to check which one breaks your application
If you are going to share lib directories like that, then each application needs to list the JAR files that it uses explicitly on the classpath. If you use a wildcard classpath entry (e.g. "lib/*"), then it is not specified which versions of the JARs will be used. The manual entry states:
Class Path Wild Cards
Class path entries can contain the base name wildcard character (), which is considered equivalent to specifying a list of all of the files in the directory with the extension .jar or .JAR. For example, the class path entry mydir/ specifies all JAR files in the directory named mydir. A class path entry consisting of * expands to a list of all the jar files in the current directory. Files are considered regardless of whether they are hidden (have names beginning with '.').
....
The order in which the JAR files in a directory are enumerated in the
expanded class path is not specified and may vary from platform to
platform and even from moment to moment on the same machine. A
well-constructed application should not depend upon any particular
order. If a specific order is required, then the JAR files can be
enumerated explicitly in the class path.
Related
I came across this question:
What is a classpath and how do I set it?
and the first answer explainns what classpath is and how to set it:
.....First, let's suppose that MyClass is something you built as part of
your project, and it is in a directory in your project called output.
The .class file would be at
output/org/javaguy/coolframework/MyClass.class (along with every other
file in that package). In order to get to that file, your path would
simply need to contain the folder 'output', not the whole package
structure, since your import statement provides all that information
to the VM.
Now let's suppose that you bundle CoolFramework up into a .jar file,
and put that CoolFramework.jar into a lib directory in your project.
You would now need to put lib/CoolFramework.jar into your classpath.
The VM will look inside the jar file for the org/javaguy/coolframework
part, and find your class.
So, classpaths contain:
JAR files, and Paths to the top of package hierarchies....
but if java only looks for classes in directories specified by CLASSPATH variable how does java find classes from libraries that are part of JRE?
I am using web application in which jar files are there in lib folder. In web.xml, servlet class is provided.how does web.xml knows in which jar file that specific class is there???
This is handled by the classloader mechanism:
A JAR file usually contains a "manifest" -- a file which lists the
contents of the JAR. The manifest can define a JAR-class-path, which
further extends the class path (but only while loading classes from
that JAR). Classes accessed by a JAR-class-path are found in the
following order:
In general, classes referenced by a JAR-class-path entry are found as
though they were part of the JAR file. The JAR files that appear in
the JAR-class-path are searched after any earlier class path entries,
and before any entries that appear later in the class path. However,
if the JAR-class-path points to a JAR file that was already searched
(for example, an extension, or a JAR file that was listed earlier in
the class path) then that JAR file will not be searched again. (This
optimization improves efficiency and prevents circular searches.) Such
a JAR file is searched at the point that it appears, earlier in the
class path. If a JAR file is installed as an extension, then any
JAR-class-path it defines is ignored. All the classes required by an
extension are presumed to be part of the SDK or to have themselves
been installed as extensions.
source
The magic word in this case is class path .
The book "Learning in Java" describes this nicely.
https://www.safaribooksonline.com/library/view/learning-java/1565927184/ch03s03.html
Java CLASSPATH variable, holds a list of locations that can be searched for packages containing Java class files. The Java interpreter and Java compiler use CLASSPATH when searching for packages and classes on the local host.
Just like we add directory location to path variable in dos/linux we can specify the location of jars in classpath variable.
Java also provided some default locations that it will look in. For example the ext directory. The path of ext folder in java on a windows installation may look like "C:\Program Files\Java\jdk1.6.0\jre\lib\ext" .
You can put your jars in the ext folder and class files in them will be automatically located..
A location on the class path can be a directory name or the name of a class archive file. Java supports archives of class files in its own Java archive ( JAR) format . This allows large groups of classes to be distributed in a single file; the Java interpreter automatically extracts individual class files from an archive,when required.
The Java interpreter knows how to find core classes, which are the classes included in every Java installation. For example , the classes in the java.lang, java.io etc. Their location need not be put in class path, the Java interpreter can find them by itself.
To find other classes, the Java interpreter searches the locations on the class path in order.
For example consider a search for the class vehicle.cars.Porche. Searching the class path directory /usr/lib/java means the interpreter looks for an individual class file at /usr/lib/java/vehicle/cars/Porche.class. If the class is present in a jar file say CompanyVehicle.jar then the compiler will be looking for vehicle.cars.Porche.class in the CompanyVehicle.jar.
To sum it up , Java has a list of location it knows it should look into. Other than that, it will look into locations you provide in classpath variable.
if you want to understand more about how classpath, classloaders work behind the scene check out the links below
How JVM starts looking for classes?
http://javapapers.com/core-java/java-class-loader/
https://en.wikipedia.org/wiki/Classpath_(Java)
I have a question around addition of specific jars from a specific folder.
Scenario:
I have a lib folder which contains a number of jar files. Due to some issue, I have to give preference to a jar file over others.
Refer this issue: http://bugzilla.slf4j.org/show_bug.cgi?id=327
Now am trying to put a specific jar file to be loaded first here log4j-1.2.17.jar
One option is I simply hardcode this in my app script to make sure this jar is always added firstly in the classpath.
Problem in the approach:
Since the project is maven based, there is a chance that log4j version changes. And in that cases I am prone to same issue again, as I have to go and change the version in the script too.
Other option (for which I am searching the solution), there is some possibility like:
Example command (Expected, but this is not working though):
java -cp <path to my app>/lib/log4j*:<path to my app>/lib/* MainClass
The advantage I see here, even if log4j version changes, I will not have to change the script.
Need inputs how can I achieve approach 2?
Thanks
According to this: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/classpath.html
Class path entries can contain the basename wildcard character , which is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR. For example, the class path entry foo/ specifies all JAR files in the directory named foo. A classpath entry consisting simply of * expands to a list of all the jar files in the current directory.
So "*" is equivalent to all *.jar files in a directory. Maybe you could put the log4j in a lib/log directory? The following is working for me under Windows:
java -cp "lib\*;lib\log\*" MainClass
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.
I setup classpath in enviroment variables i set a user variable named classpath with value= .;C:\Users\Borut\Downloads\httpcomponents-client-4.1.2-bin\lib
the directory is full of .jar files. yet still when i run a program through cmd it reports an error that the package from the class does not exist.
Historically, you've needed to include the jar files themselves, not the directory they're in, on the CLASSPATH. In recent JREs, you can use a wildcard (i.e., a path ending in /*) to indicate all the jars in a directory. But if you indicate only a directory, then that directory is searched for class files and packages only; jar files are ignored.
You need to either (a) explicitly list the jar files, or (b) use a wildcard classpath (1.6+).