Posts Tagged ‘classpath’
[DevoxxFR2013] The Classpath Persists, Yet Its Days Appear Numbered
Lecturer
Alexis Hassler has devoted more than fifteen years to Java development. Operating independently, he engages in programming while also guiding enterprises through training and advisory roles to refine their Java-based workflows and deployment strategies. As co-leader of the Lyon Java User Group, he plays a pivotal part in orchestrating community gatherings, including the acclaimed annual Mix-IT conference held in Lyon.
Abstract
Alexis Hassler meticulously examines the enduring complexities surrounding Java’s classpath and classloading mechanisms, drawing a sharp contrast between conventional hierarchical approaches and the rise of sophisticated modular frameworks. By weaving historical insights with hands-on illustrations and deep integration of JBoss Modules, he unravels the intricacies of dependency clashes, application isolation techniques, and viable transition pathways. The exploration extends to profound consequences for application server environments, delivering practical remedies to alleviate classpath-induced frustrations while casting an anticipatory gaze toward the transformative potential of Jigsaw.
Tracing the Roots: Classloaders and the Enduring Classpath Conundrum
Hassler opens by invoking Mark Reinhold’s bold 2009 JavaOne proclamation that the classpath’s demise was imminent, a statement that fueled expectations of modular systems seamlessly resolving all dependency conflicts. Despite the passage of four years, the classpath remains a fixture within the JDK and application server landscapes, underscoring its stubborn resilience.
Within the JDK, classloaders operate through a delegation hierarchy: the Bootstrap classloader handles foundational rt.jar components, the Extension classloader manages optional javax packages, and the Application classloader oversees user-defined code. This parent-first delegation model effectively safeguards core class integrity yet frequently precipitates version mismatches when disparate libraries demand conflicting implementations.
Hassler vividly demonstrates notorious pitfalls, such as the perplexing ClassNotFoundException that arises despite a JAR’s presence in the classpath or the insidious NoDefClassError triggered by incompatible transitive dependencies. These issues originate from the classpath’s flat aggregation paradigm, which indiscriminately merges all artifacts without regard for scoping or versioning nuances.
Hierarchical Containment Strategies in Application Servers: The Tomcat Paradigm
Application servers like Tomcat invert the delegation flow to enforce robust isolation among deployed artifacts. The WebappClassLoader prioritizes local resources before escalating unresolved requests to parent loaders, thereby permitting each web application to maintain its own dependency ecosystem.
This inverted hierarchy facilitates per-application versioning, substantially mitigating library collisions. Hassler delineates Tomcat’s layered loader architecture, encompassing common, server, shared, and per-webapp classloaders, each serving distinct scoping responsibilities.
Nevertheless, memory leaks persist as a formidable challenge, particularly during hot redeployments when static fields retain references to obsolete classes, inflating PermGen space. Mitigation demands meticulous resource cleanup through context listeners and disciplined finalization practices.
Modular Paradigms on the Horizon: OSGi, Jigsaw, and the Pragmatism of JBoss Modules
OSGi introduces the concept of bundles equipped with explicit import and export declarations, complete with version range specifications. This dynamic loading and unloading capability proves ideal for plugin architectures, though it necessitates substantial refactoring of existing codebases.
Project Jigsaw, slated for Java 9, aspires to embed modularity natively through module declarations that articulate precise dependencies. Despite repeated delays, its eventual integration promises standardized resolution, yet its absence compels interim solutions.
JBoss Modules, already battle-tested within JBoss AS7, employs a dependency graph resolution mechanism. Modules are defined with dedicated resource paths and dependency linkages, enabling parallel coexistence of multiple library versions. Hassler elucidates a module descriptor:
<module xmlns="urn:jboss:module:1.1" name="com.example.app">
<resources>
<resource-root path="app.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.hibernate" slot="4.3"/>
</dependencies>
</module>
This structure empowers fine-grained version isolation, exemplified by simultaneous deployment of Hibernate 3 and 4 instances.
Hands-On Deployment Scenarios: JBoss Modules in Standalone and Tomcat Environments
Within JBoss AS7, modules reside in a dedicated directory structure, and applications declare dependencies via jboss-deployment-structure.xml manifests. Standalone execution leverages module-aware classloaders, either through MANIFEST entries or programmatic instantiation.
Hassler showcases a proof-of-concept integration with Tomcat, wherein a custom ClassLoader delegates to JBoss Modules, thereby endowing legacy web containers with modern dependency management. The prototype, available on GitHub, acknowledges limitations in hot-redeployment memory cleanup but validates conceptual soundness.
This adaptability extends modular benefits to environments traditionally tethered to classpath constraints.
Forward-Looking Consequences for Java Ecosystems: Transition Pathways and Jigsaw’s Promise
Classpath tribulations exact a heavy toll on developer productivity, manifesting in protracted debugging sessions and fragile builds. Modular frameworks counter these by enhancing maintainability, accelerating startup through lazy initialization, and fortifying deployment reliability.
Migration hurdles encompass tooling maturity and knowledge gaps, yet the advantages—conflict elimination, streamlined packaging—outweigh transitional friction. Hassler advocates incremental adoption, leveraging JBoss Modules as a bridge to Jigsaw’s eventual standardization.
In conclusion, while the classpath lingers, modular evolution heralds its obsolescence, equipping practitioners with robust tools to transcend historical limitations.
Links:
java.lang.IncompatibleClassChangeError: Implementing class
Case: on a call to:
JAXBContext.newInstance(Field.class, FieldSet.class);
I had a:
java.lang.IncompatibleClassChangeError: Implementing class
Complete stacktrace:
java.lang.IncompatibleClassChangeError: Implementing class at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:139) at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:117) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210) at javax.xml.bind.ContextFinder.find(ContextFinder.java:368) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522) (...) |
Fix: there an issue of classpath and a conflit of jars. Remove all jaxb-* jars from within your classpath, except the jaxb-impl.jar that you must keep.