How to Resolve Java Jar Conflicts by Adjusting Classloader Order
This article explains why manual jar management can cause class loading conflicts, shows quick IDE-based steps to reorder jars for a temporary fix, and dives into JVM classloader isolation, the parent‑delegation mechanism, and Tomcat's startup loading order to help developers debug and prevent such issues.
Background
Many legacy projects still add JAR files manually to a lib directory and configure IDE dependencies one by one. This approach is error‑prone, leads to frequent JAR conflicts, and makes troubleshooting rely on experience. The author encountered a case where the application started on one developer's machine but failed on another with a missing‑class error.
Temporary Fix
When a full refactor is not possible, a quick workaround is to adjust the loading order of the JARs so that the correct version is loaded first.
Locate the missing class in the IDE (e.g., Command+Shift+N in IDEA on macOS).
Identify which JAR should provide that class (e.g., spring‑core instead of spring.jar).
Manually reorder the JAR entries in the build path so the desired JAR is loaded before the conflicting one. Both Eclipse and IDEA allow this adjustment.
In Eclipse, open the build path configuration and move the required JAR upward. In IDEA, edit the module dependencies and drag the JAR to a higher position.
Classloader Isolation and Parent Delegation
The temporary fix relies on understanding two JVM concepts: classloader isolation and the parent‑delegation mechanism.
Classloader Isolation
Each classloader has its own namespace. When it loads a class, it searches for the fully qualified class name (FQCN) in its namespace. If a class with the same FQCN has already been loaded by that classloader, subsequent identical classes are ignored, which can cause ClassNotFoundException or method‑missing errors when the wrong JAR was loaded first.
Parent Delegation Mechanism
The JVM delegates class‑loading requests upward: a child classloader first asks its parent, and only if the parent cannot find the class does the child attempt to load it. This two‑step process (bottom‑up check, then top‑down load) ensures a consistent view of core classes.
ClassLoader Loading Process
The standard JDK classloaders follow a specific order: AppClassLoader delegates to ExtClassLoader. ExtClassLoader delegates to BootStrapClassLoader.
If BootStrapClassLoader cannot find the class in $JAVA_HOME/jre/lib, ExtClassLoader tries.
If that also fails, AppClassLoader attempts loading; failure results in ClassNotFoundException.
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}Jar Loading Order
The order in which JARs are loaded determines which version of a class is chosen. Two main factors influence this order:
The position of the JAR in the classloader hierarchy (different classloaders have different priorities).
The file‑system enumeration order, which can vary between environments (e.g., Tomcat or Resin may list files unsorted).
In the author's case, differing file‑system order caused the same directory to load JARs in a different sequence, leading to a conflict.
Typical Symptoms of Jar Conflicts
java.lang.ClassNotFoundException– the required class is absent. java.lang.NoSuchMethodError – the loaded version lacks the expected method. java.lang.NoClassDefFoundError or java.lang.LinkageError – similar version mismatches.
Unexpected runtime behavior without exceptions – the wrong implementation was loaded.
Tomcat Startup Jar and Class Loading Order
$JAVA_HOME/lib – core Java APIs.
$JAVA_HOME/lib/ext – extension JARs.
Classpath directories specified via -classpath or -Djava.class.path.
$CATALINA_HOME/common (loaded top‑down).
$CATALINA_HOME/server (loaded top‑down).
$CATALINA_BASE/shared (loaded top‑down).
WEB-INF/classes – compiled classes.
WEB-INF/lib – application JARs.
Within each directory, JARs are loaded sequentially; once a class is loaded, later identical classes are ignored.
Conclusion
Jar conflicts are common in Java development. Understanding the root cause, JVM classloader mechanics, and loading order enables faster debugging and stronger interview performance. Future articles will explore Maven’s conflict‑resolution strategies such as dependency mediation, shortest‑path, and first‑declared‑wins.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
