I've got a question regarding the guarantees, if any, in the following scenario (note that the question is not "How to do this in a different way?", the question is really about class loading order in the following case (to better understand how class loading works).
Here's the hypothetical scenario... There's a .war file that has the following (partial) directory structure:
WEB-INF/classes/com/acme/Bunny.class
.
.
.
WEB-INF/lib/acme.jar
Both Bunny.class files have import referencing other classes from acme.jar
Bunny.class in WEB-INF/classes/... is the only class that has the same name/path that a class from acme.jar.
The .jar file acme.jar also contains com.acme.Bunny (and there are a no special class loader tricks used).
I understand that the Java spec guarantees that a class won't be loaded until it is actually used (or "manually class-loaded" on purpose) by the program, which is why if you stuff thousands of .jar, say, in a .war, the classloader(s) don't start classloading tens of thousands of classes.
(edit)
But what about the order in which the
two classes in the examples above are
loaded?
should have been phrased:
But how is it decided which one of the
two classes above is loaded?
or something like that :)
There's one guarantee made: com.acme.Bunny shall be used before any other class from com.acme....
Basically, on Wikipedia, the following is written:
The most complex JAR hell problems
arise in circumstances that take
advantage of the full complexity of
the classloading system. A Java
program is not required to use only a
single "flat" classloader, but instead
may be composed of several (or, in
fact, an indefinite number of) nested,
cooperating classloaders. Classes
loaded by different classloaders may
interact in complex ways not fully
comprehended by a developer, leading
to inexplicable errors or bugs.
So I'm wondering: can I be sure that /classes/com/acme/Bunny.class will be classloaded before the one from .jar inside the WEB-INF/lib/ dir or not?
This question may be of some help.
The servlet specification is vague on this. One would expect "WEB-INF/classes" to be searched before "WEB-INF/lib" but it seems that it's up to the servlet container to decide. All you can be sure of is that the container should consistently load one before the other, so you should never see both classes in the same container. The search path may be configurable, depending on your container.
Sorry I can't be more specific: welcome to the world of multiple servlet containers. Don't get me started on Websphere fun-and-games.
The selected answer is wrong. Servlet spec version 2.4 and 3.0 clearly states that WEB-INF/classes are loaded first and then WEB-INF/lib
Servlet 2.4: http://download.oracle.com/otn-pub/jcp/servlet-2.4-fr-spec-oth-JSpec/servlet-2_4-fr-spec.pdf - section SRV.9.5, last paragraph
Servlet 3.0: http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf - section 10.5, last paragraph
The Web application class loader must load classes from the WEB-INF/classes
directory first, and then from library JARs in the WEB-INF/lib directory.
Both the WEB-INF/lib/*.jar
files and the WEB-INF/classes
directory are in the same ClassLoader. It would be as if you started an application with all the jars listed in the ClassPath. As a class name needs to be resolved, the ClassLoader will find the first class that matches from its resources. The exact order it searches in is nondeterministic--it depends on the platform.
Java Packages were designed to address the problem of name clashes such as what you described. It is never a good idea to deliberately name a class the same as what is bundled in its own jar file. The better solution would be to extend the class and use the new version in your code. If you need to alter functionality of that class, then you might look into the black magic of Java Aspect Oriented Programming.
The answer depends entirely on the concrete class loader hierarchy in use. While the JVM will provide a system class loader, Java EE application servers will typically use custom ClassLoader implementations to isolate classes loaded in separate modules and applications, and to enforce security concerns.
The ClassLoader API does not impose any rules on how concrete implementations resolve class requests. However, the intent of the WEB-INF/lib directory is to allow bundling of app-specific libraries. I suspect most people would expect the jar files in the lib directory to be searched AFTER the root contents of the jar file.
I'm not aware that the Java EE specifications establish any such guarantee though, and the interface and documentation for the abstract ClassLoader class certainly doesn't.
So, hypothetically, you could have a web container that would end up returning Bunny.class from the jar file instead of the one from the root hierarchy of the war file.
It depends on the container that deploys the war file. From my experiences, WEB-INF/classes location is always before lib/ on the classpath of a classloader for application context.
Classes are loaded right after the deployer expands the war into the container. Usually when a context loader listener servlet is loaded and the rest of the application with it. It can be done in many ways such as by a reference to default servlet or loading spring context etc.
So that WEB-INF/classes/com/acme/Bunny.class should be loaded first afaik.
You seem to be conflating two different senses of "before".
Classes are loaded in the order they are used. This is temporal, and is the more correct use of "before". If Foo is used before Bar then it'll be loaded before Bar.
You're also talking about whether classes/com/acme/Bunny.class will be loaded "before" acme.jar's com/acme/Bunny.class. The second one won't be loaded at all. The classloader will look for the first instance of com/acme/Bunny.class on the classpath, find the one in classes, and stop looking.