Aren't JAR files modular enough?
JAR files and the deployment environment in which they operate greatly
improve on the many legacy deployment conventions otherwise available.
But JAR files have no intrinsic uniqueness, apart from a rarely used
version number, which is hidden in a .jar manifest. The JAR file and
the optional manifest are not used as modularity conventions within
the Java runtime environment. So the package names of classes in the
file and their participation in a classpath are the only parts of the
JAR structure that lend modularity to the runtime environment.
In short, JARs are a good attempt at modularization, but they don't
fulfill all the requirements for a truly modular environment.
Frameworks and platforms like Spring and OSGi use patterns and
enhancements to the JAR specification to provide environments for
building very capable and modular systems. Over time, however, even
these tools will succumb to a very unfortunate side-effect of the JAR
specification JAR hell!
Classpath/JAR hell
When the Java runtime environment allows for arbitrarily complex JAR
loading mechanisms, developers know they are in classpath hell or JAR
hell. A number of configurations can lead to this condition.
First, consider a situation where a Java application developer
provides an updated version of the application and has packaged it in
a JAR file with the exact same name as the old version. The Java
runtime environment provides no validation facilities for determining
the correct JAR file. The runtime environment will simply load classes
from the JAR file that it finds first or that satisfies one of many
classpath rules. This leads to unexpected behavior at best.
Another instance of JAR hell arises where two or more applications or
processes depend on different versions of a third-party library. Using
standard class-loading facilities, only one version of the third-party
library will be available at runtime, leading to errors in at least
one application or process.
A full-featured and efficient Java module system should facilitate
separation of code into distinct, easily understood, and loosely
coupled modules. Dependencies should be clearly specified and strictly
enforced. Facilities should be available that allow modules to be
upgraded without having a negative effect on other modules. A modular
runtime environment should enable configurations that are specific to
a particular domain or vertical market, thus reducing the startup time
and system footprint of the environment.
Modularity solutions for Java
Along with the modularity features mentioned so far, recent efforts
add a few more. The following features are intended to optimize
performance and enable extending the runtime environment:
Segmented source code:
Source code separated into distinct, cached segments, each of which
contains a specific type of compiled code. The goals of which include
skipping non-method code during garbage sweeps, incremental builds,
and better memory management.
Build-time enforcements: Language constructs to enforce namespaces,
versioning, dependencies, and others.
Deployment facilities: Support
for deploying scaled runtime environments according to specific needs,
such as those of a mobile device environment