The Java Module System

Book description

Java's much-awaited "Project Jigsaw" is finally here! Java 11 includes a built-in modularity framework, and The Java Module System is your guide to discovering it. In this new book, you'll learn how the module system improves reliability and maintainability, and how it can be used to reduce tight coupling of system components.



About the Technology

Packaging code into neat, well-defined units makes it easier to deliver safe and reliable applications. The Java Platform Module System is a language standard for creating these units. With modules, you can closely control how JARs interact and easily identify any missing dependencies at startup. This shift in design is so fundamental that starting with Java 9, all core Java APIs are distributed as modules, and libraries, frameworks, and applications will benefit from doing the same.



About the Book

The Java Module System is your in-depth guide to creating and using Java modules. With detailed examples and easy-to-understand diagrams, you’ll learn the anatomy of a modular Java application. Along the way, you’ll master best practices for designing with modules, debugging your modular app, and deploying to production.



What's Inside

  • The anatomy of a modular Java app
  • Building modules from source to JAR
  • Migrating to modular Java
  • Decoupling dependencies and refining APIs
  • Handling reflection and versioning
  • Customizing runtime images
  • Updated for Java 11


About the Reader

Perfect for developers with some Java experience.



About the Author

Nicolai Parlog is a developer, author, speaker, and trainer. His home is codefx.org.

We interviewed Nicolai as a part of our Six Questions series. Check it out here.



Quotes
Nicolai’s care and attention to detail allow you to take advantage of the distillation of his knowledge—from theory to practice, from entry level to advanced.
- From the Foreword by Kevlin Henney

A great introduction to modules in general, and Java 11 modules in particular.
- Mikkel Arentoft, Danske Bank

A clear and concise introduction to Java’s long-awaited module system.
- Jim Wright, Sword Apak

If you are serious about Java 11, you will need this book!
- Christian Kreutzer-Beck, ARAG Italy

Publisher resources

View/Submit Errata

Table of contents

  1. The Java Module System
  2. Copyright
  3. dedication
  4. contents
  5. front matter
    1. foreword
    2. preface
    3. acknowledgments
    4. about this book
      1. Who should read this book
      2. How this book is organized: a roadmap
      3. Watch out for these
      4. About the code
      5. liveBook discussion forum
    5. about the author
    6. about the cover illustration
  6. Part 1. Hello, modules
  7. 1 First piece of the puzzle
    1. 1.1 What is modularity all about?
      1. 1.1.1 Visualizing software as graphs
      2. 1.1.2 The impact of design principles
      3. 1.1.3 What modularity is all about
    2. 1.2 Module erasure before Java 9
    3. 1.3 Complications before Java 9
      1. 1.3.1 Unexpressed dependencies between JARs
      2. 1.3.2 Shadowing classes with the same name
      3. 1.3.3 Conflicts between different versions of the same project
      4. 1.3.4 Complex class loading
      5. 1.3.5 Weak encapsulation across JARs
      6. 1.3.6 Security checks have to be handcrafted
      7. 1.3.7 Poor startup performance
      8. 1.3.8 Rigid Java runtime
    4. 1.4 Bird’s-eye view of the module system
      1. 1.4.1 Everything is a module
      2. 1.4.2 Your first module
      3. 1.4.3 The module system in action
      4. 1.4.4 Your non-modular project will be fine—mostly
    5. 1.5 Goals of the module system
      1. 1.5.1 Reliable configuration: Leaving no JAR behind
      2. 1.5.2 Strong encapsulation: Making module-internal code inaccessible
      3. 1.5.3 Automated security and improved maintainability
      4. 1.5.4 Improved startup performance
      5. 1.5.5 Scalable Java platform
      6. 1.5.6 Non-goals
    6. 1.6 Skills, old and new
      1. 1.6.1 What you’ll learn
      2. 1.6.2 What you should know
    7. Summary
  8. 2 Anatomy of a modular application
    1. 2.1 Introducing ServiceMonitor
    2. 2.2 Modularizing ServiceMonitor
    3. 2.3 Cutting ServiceMonitor into modules
    4. 2.4 Laying out files in a directory structure
    5. 2.5 Declaring and describing modules
      1. 2.5.1 Declaring dependencies on other modules
      2. 2.5.2 Defining a module’s public API
      3. 2.5.3 Visualizing ServiceMonitor with the module graph
    6. 2.6 Compiling and packaging modules
    7. 2.7 Running ServiceMonitor
    8. 2.8 Extending a modular code base
    9. 2.9 Post mortem: Effects of the module system
      1. 2.9.1 What the module system does for you
      2. 2.9.2 What else the module system can do for you
      3. 2.9.3 Allowing optional dependencies
    10. Summary
  9. 3 Defining modules and their properties
    1. 3.1 Modules: The building blocks of modular applications
      1. 3.1.1 Java modules (JMODs), shipped with the JDK
      2. 3.1.2 Modular JARs: Home-grown modules
      3. 3.1.3 Module declarations: Defining a module’s properties
      4. 3.1.4 The many types of modules
    2. 3.2 Readability: Connecting the pieces
      1. 3.2.1 Achieving reliable configuration
      2. 3.2.2 Experimenting with unreliable configurations
    3. 3.3 Accessibility: Defining public APIs
      1. 3.3.1 Achieving strong encapsulation
      2. 3.3.2 Encapsulating transitive dependencies
      3. 3.3.3 Encapsulation skirmishes
    4. 3.4 The module path: Letting Java know about modules
      1. 3.4.1 Module resolution: Analyzing and verifying an application’s structure
      2. 3.4.2 Module graph: Representation of an application’s structure
      3. 3.4.3 Adding modules to the graph
      4. 3.4.4 Adding edges to the graph
      5. 3.4.5 Accessibility is an ongoing effort
    5. Summary
  10. 4 Building modules from source to JAR
    1. 4.1 Organizing your project in a directory structure
      1. 4.1.1 New proposal—new convention?
      2. 4.1.2 Established directory structure
      3. 4.1.3 The place for module declarations
    2. 4.2 Compiling a single module
      1. 4.2.1 Compiling modular code
      2. 4.2.2 Modular or non-modular?
    3. 4.3 Compiling multiple modules
      1. 4.3.1 The naive approach
      2. 4.3.2 The module source path: Informing the compiler about the project structure
      3. 4.3.3 The asterisk as a token for the module name
      4. 4.3.4 Multiple module source path entries
      5. 4.3.5 Setting the initial module
      6. 4.3.6 Is it worth it?
    4. 4.4 Compiler options
    5. 4.5 Packaging a modular JAR
      1. 4.5.1 Quick recap of jar
      2. 4.5.2 Analyzing a JAR
      3. 4.5.3 Defining an entry point
      4. 4.5.4 Archiver options
    6. Summary
  11. 5 Running and debugging modular applications
    1. 5.1 Launching the JVM with modules
      1. 5.1.1 Specifying the main class
      2. 5.1.2 If the initial module and main module aren’t the same
      3. 5.1.3 Passing parameters to the application
    2. 5.2 Loading resources from modules
      1. 5.2.1 Resource loading before Java 9
      2. 5.2.2 Resource loading on Java 9 and later
      3. 5.2.3 Loading package resources across module boundaries
    3. 5.3 Debugging modules and modular applications
      1. 5.3.1 Analyzing individual modules
      2. 5.3.2 Validating sets of modules
      3. 5.3.3 Validating a module graph
      4. 5.3.4 Listing observable modules and dependencies
      5. 5.3.5 Excluding modules during resolution
      6. 5.3.6 Observing the module system with log messages
    4. 5.4 Java Virtual Machine options
    5. Summary
  12. Part 2. Adapting real-world projects
  13. 6 Compatibility challenges when moving to Java 9 or later
    1. 6.1 Working with JEE modules
      1. 6.1.1 Why are the JEE modules special?
      2. 6.1.2 Manually resolving JEE modules
      3. 6.1.3 Dropping in third-party implementations of JEE modules
    2. 6.2 Casting to URLClassLoader
      1. 6.2.1 Application class loaders, then and now
      2. 6.2.2 Getting by without URLClassLoader
      3. 6.2.3 Finding troublesome casts
    3. 6.3 Updated run-time image directory layout
    4. 6.4 Selecting, replacing, and extending the platform
      1. 6.4.1 No more compact profiles
      2. 6.4.2 Extension mechanism removed
      3. 6.4.3 Endorsed standards override mechanism removed
      4. 6.4.4 Some boot class path options removed
      5. 6.4.5 No compilation for Java 5
      6. 6.4.6 JRE version selection removed
    5. 6.5 Little things that make big things fail
      1. 6.5.1 New version strings
      2. 6.5.2 Tool exodus
      3. 6.5.3 The littlest things
      4. 6.5.4 New deprecations in Java 9, 10, and 11
    6. Summary
  14. 7 Recurring challenges when running on Java 9 or later
    1. 7.1 Encapsulation of internal APIs
      1. 7.1.1 Internal APIs under the microscope
      2. 7.1.2 Analyzing dependencies with JDeps
      3. 7.1.3 Compiling against internal APIs
      4. 7.1.4 Executing against internal APIs
      5. 7.1.5 Compiler and JVM options for accessing internal APIs
    2. 7.2 Mending split packages
      1. 7.2.1 What’s the problem with split packages?
      2. 7.2.2 The effects of split packages
      3. 7.2.3 Many ways to handle split packages
      4. 7.2.4 Patching modules: Last resort for handling split packages
      5. 7.2.5 Finding split packages with JDeps
      6. 7.2.6 A note on dependency version conflicts
    3. Summary
  15. 8 Incremental modularization of existing projects
    1. 8.1 Why incremental modularization is an option
      1. 8.1.1 If every JAR had to be modular …
      2. 8.1.2 Mixing and matching plain JARs with modules
      3. 8.1.3 Technical underpinnings of incremental modularization
    2. 8.2 The unnamed module, aka the class path
      1. 8.2.1 The chaos of the class path, captured by the unnamed module
      2. 8.2.2 Module resolution for the unnamed module
      3. 8.2.3 Depending on the unnamed module
    3. 8.3 Automatic modules: Plain JARs on the module path
      1. 8.3.1 Automatic module names: Small detail, big impact
      2. 8.3.2 Module resolution for automatic modules
      3. 8.3.3 All in on automatic modules?
      4. 8.3.4 Depending on automatic modules
    4. Summary
  16. 9 Migration and modularization strategies
    1. 9.1 Migration strategies
      1. 9.1.1 Preparatory updates
      2. 9.1.2 Estimating the effort
      3. 9.1.3 Continuously build on Java 9+
      4. 9.1.4 Thoughts on command-line options
    2. 9.2 Modularization strategies
      1. 9.2.1 Bottom-up modularization: If all project dependencies are modular
      2. 9.2.2 Top-down modularization: If an application can’t wait for its dependencies
      3. 9.2.3 Inside-out modularization: If a project is in the middle of the stack
      4. 9.2.4 Applying these strategies within a project
    3. 9.3 Making JARs modular
      1. 9.3.1 Open modules as an intermediate step
      2. 9.3.2 Generating module declarations with JDeps
      3. 9.3.3 Hacking third-party JARs
      4. 9.3.4 Publishing modular JARs for Java 8 and older
    4. Summary
  17. Part 3. Advanced module system features
  18. 10 Using services to decouple modules
    1. 10.1 Exploring the need for services
    2. 10.2 Services in the Java Platform Module System
      1. 10.2.1 Using, providing, and consuming services
      2. 10.2.2 Module resolution for services
    3. 10.3 Designing services well
      1. 10.3.1 Types that can be services
      2. 10.3.2 Using factories as services
      3. 10.3.3 Isolating consumers from global state
      4. 10.3.4 Organizing services, consumers, and providers into modules
      5. 10.3.5 Using services to break cyclic dependencies
      6. 10.3.6 Declaring services across different Java versions
    4. 10.4 Accessing services with the ServiceLoader API
      1. 10.4.1 Loading and accessing services
      2. 10.4.2 Idiosyncrasies of loading services
    5. Summary
  19. 11 Refining dependencies and APIs
    1. 11.1 Implied readability: Passing on dependencies
      1. 11.1.1 Exposing a module’s dependencies
      2. 11.1.2 The transitive modifier: Implying readability on a dependency
      3. 11.1.3 When to use implied readability
      4. 11.1.4 When to rely on implied readability
      5. 11.1.5 Refactoring modules with implied readability
      6. 11.1.6 Refactoring modules by merging them
    2. 11.2 Optional dependencies
      1. 11.2.1 The conundrum of reliable configuration
      2. 11.2.2 The static modifier: Marking dependencies as optional
      3. 11.2.3 Module resolution of optional dependencies
      4. 11.2.4 Coding against optional dependencies
    3. 11.3 Qualified exports: Limiting accessibility to specific modules
      1. 11.3.1 Exposing internal APIs
      2. 11.3.2 Exporting packages to modules
      3. 11.3.3 When to use qualified exports
      4. 11.3.4 Exporting packages on the command line
    4. Summary
  20. 12 Reflection in a modular world
    1. 12.1 Why exports directives aren’t a good fit for reflection
      1. 12.1.1 Breaking into non-modular code
      2. 12.1.2 Forcing the publication of internal types
      3. 12.1.3 Qualified exports create coupling to specific modules
      4. 12.1.4 No support for deep reflection
    2. 12.2 Open packages and modules: Designed for the reflection use case
      1. 12.2.1 Opening packages to run-time access
      2. 12.2.2 Opening packages for specific modules
      3. 12.2.3 Exporting vs. opening packages
      4. 12.2.4 Opening modules: Reflection closeout
    3. 12.3 Reflecting over modules
      1. 12.3.1 Updating reflecting code for modules (or not)
      2. 12.3.2 Using variable handles instead of reflection
      3. 12.3.3 Analyzing module properties with reflection
      4. 12.3.4 Modifying module properties with reflection
      5. 12.3.5 Forwarding open packages
    4. 12.4 Dynamically creating module graphs with layers
      1. 12.4.1 What are layers?
      2. 12.4.2 Analyzing layers
      3. 12.4.3 Creating module layers
    5. Summary
  21. 13 Module versions: What’s possible and what’s not
    1. 13.1 The lack of version support in the JPMS
      1. 13.1.1 No support for multiple versions
      2. 13.1.2 No support for version selection
      3. 13.1.3 What the future may bring
    2. 13.2 Recording version information
      1. 13.2.1 Recording versions while building modules
      2. 13.2.2 Accessing module versions
    3. 13.3 Running multiple versions of a module in separate layers
      1. 13.3.1 Why you need a starter to spin up additional layers
      2. 13.3.2 Spinning up layers for your application, Apache Twill, and Cassandra Java Driver
    4. Summary
  22. 14 Customizing runtime images with jlink
    1. 14.1 Creating custom runtime images
      1. 14.1.1 Getting started with jlink
      2. 14.1.2 Image content and structure
      3. 14.1.3 Including services in runtime images
      4. 14.1.4 Right-sizing images with jlink and jdeps
    2. 14.2 Creating self-contained application images
      1. 14.2.1 Including application modules in images
      2. 14.2.2 Generating a native launcher for your application
      3. 14.2.3 Security, performance, and stability
    3. 14.3 Generating images across operating systems
    4. 14.4 Using jlink plugins to optimize images
      1. 14.4.1 Plugins for jlink
      2. 14.4.2 Reducing image size
      3. 14.4.3 Improving run-time performance
    5. 14.5 Options for jlink
    6. Summary
  23. 15 Putting the pieces together
    1. 15.1 Adding bells and whistles to ServiceMonitor
      1. 15.1.1 Diversified dependencies
      2. 15.1.2 Reduced visibility
      3. 15.1.3 Decoupled with services
      4. 15.1.4 Loads code at run time with layers
      5. 15.1.5 Handles dependencies on plain JARs
    2. 15.2 Tips for a modular application
      1. 15.2.1 Modular or not?
      2. 15.2.2 The ideal module
      3. 15.2.3 Take care of your module declarations
      4. 15.2.4 Breaking code by editing module declarations
    3. 15.3 The technology landscape
      1. 15.3.1 Maven, Gradle, and other build tools
      2. 15.3.2 OSGi
      3. 15.3.3 Microservices
    4. 15.4 Thoughts on a modular ecosystem
    5. Summary
  24. Appendix A. Class-path recap
    1. A.1 Using the class path to load application JARs
    2. A.2 The class path since Java 9
  25. Appendix B. High-level introduction to the reflection API
    1. B.1 Fundamental types and methods
    2. B.2 Breaking into APIs with setAccessible
    3. B.3 Annotations mark code for reflection
  26. Appendix C. Observing the JVM with unified logging
    1. C.1 What is unified logging?
    2. C.2 Defining which messages should be shown
    3. C.3 Defining where messages should go
    4. C.4 Defining what messages should say
    5. C.5 Configuring the entire logging pipeline
  27. Appendix D. Analyzing a project’s dependencies with JDeps
    1. D.1 Getting to know JDeps
    2. D.2 Including dependencies in the analysis
    3. D.3 Configuring JDeps’ output
    4. D.4 Drilling deeper into your project’s dependencies
    5. D.5 JDeps understands modules
  28. Appendix E. Targeting multiple Java versions with multi-release JARs
    1. E.1 Creating a multi-release JAR
    2. E.2 Internal workings of MR-JARs
    3. E.3 Usage recommendations
      1. E.3.1 Organizing the source code
      2. E.3.2 Organizing the bytecode
      3. E.3.3 When to use MR-JARs
  29. Index
  30. Lists of Figures, Tables and Listings
    1. List of Illustrations
    2. List of Tables
    3. List of Listings

Product information

  • Title: The Java Module System
  • Author(s): Nicolai Parlog
  • Release date: July 2019
  • Publisher(s): Manning Publications
  • ISBN: 9781617294280