Home » Java » Benefits of JPMS/Project Jigsaw for Small Applications / Libraries

Benefits of JPMS/Project Jigsaw for Small Applications / Libraries

Posted by: admin December 28, 2021 Leave a comment

Questions:

I understand the benefits of the Java Platform Module System (JPMS) for large applications, but is there any reason to make a small library or application into a (single) module? If so, are Modular Jar Files the best means of accomplishing this, or is the normal approach preferred?

Going forward, will there be performance implications for modularized v. classpath programs?

Answers:

Immediate performance implications include the following:

  • Modularized applications can opt to use jlink so that the distributable runtime is reduced in size: it only uses the modules you require. So if you don’t need Swing, Corba, etc, it does not reside on disk. (more info here).
  • Modularized applications use the module graph for classloading; the algorithm for this is much faster than the linear search of classpath (more info here).

This is by no means a guarantee that your app will be faster, but the above is undeniably attractive.

Longer term, consider this:

  • Though experimental in JDK 9, there is an AOT compiler that (for Linux x64) will compile the java.base module to native code. This is likely the path forward for future Java releases. Surely this will improve startup time in the future. (again, more info here)

###

If so, are Modular Jar Files the best means of accomplishing this, or is the normal approach preferred?

I’m not sure what you you mean by “the normal approach” – modular JARs are the “normal approach” to create artifacts that the module system will create a module for.

[I]s there any reason to make a small library or application into a (single) module?

Yes, a few:

  • Developers creating a modular application or using a modular library benefit from reliable configuration, where they can only launch their application if all dependencies are present – this is a benefit no matter how large the application/library is.

  • As a library designer you can hide internals. While strong encapsulation is only effective if your modular JAR is put onto the module path, the module descriptor still documents your intent in code, and allows you to more unscrupulously change your code. Application developers benefit as well because they can no longer accidentally depend on unsupported implementation details.

  • Even in small applications and libraries, services might be used to decouple different aspects of functionality and make code more easily extensible.

  • Only “real” modules (as opposed to automatic modules) can be included in a runtime image by jlink. Not providing a modular JAR robs your users of a library of that possibility.

Also note that you never know which small application or library might turn into something bigger. 🙂

Going forward, will there be performance implications for modularized v. classpath programs?

While building the module graph and verifying modules costs time, the module system should make it up with an improved class loading strategy: It records for every package which module exports it and loads types from that package directly from that module instead of having to scan the entire class path. either way, I don’t think this should be a deciding factor.

###

Found this link informative
http://www.javaworld.com/article/2878952/java-platform/modularity-in-java-9.html

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