Alexandru Jecan
Alexandru Jecan
Munich, Germany
Any source code or other supplementary material referenced by the author in this book is available to readers on GitHub via the book’s product page, located at www.apress.com/us/book/9781484227121 . For more detailed information, please visit www.apress.com/source-code .
ISBN 978-1-4842-2712-1
e-ISBN 978-1-4842-2713-8
https://doi.org/10.1007/978-1-4842-2713-8
Library of Congress Control Number: 2017954918
© Alexandru Jecan 2017
This work is subject to copyright. All rights are solely and exclusively licensed by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or omissions that may be made. The publisher makes no warranty, express or implied, with respect to the material contained herein.
Printed on acid-free paper
To my wife, Diana, who sustains me and encourages me every day in all my efforts. To my parents, Alexandrina and Eugen, who provided me with a very good education since I was a young child. Thank you and I love you.
The Java programming language, introduced in 1995, has had a very successful story. It’s evolved constantly since its birth and became one of the most popular programming languages in the world. Every new release of Java has added new features—small, medium, and big.
Java 9 is finally here! It is scheduled for release in September 2017, more than three years after the release of Java 8.
The release of Java 8 in March 2014 brought very important features to the Java platform like Lambdas and the Stream API, which were definitely needed by developers. Nevertheless, some well-known weaknesses of the platform had still not been addressed in Java 8: the huge monolithic JDK and the class path. These problems are addressed in Java 9 by Project Jigsaw.
The most important feature of Java 9 is by far the new modular system it introduced. Other new features have been introduced in Java 9, but they’re not the focus of this book. This book covers the new modular system introduced in Java 9. The big, monolithic, and indivisible JDK has been problematic for a long time. It’s difficult to install it on small devices because many don’t have enough memory to hold it. In many cases, a large number of classes that comprise the JDK aren’t needed because the application may not require them. CORBA, for instance, is still part of the JDK, but it’s rarely used in real projects today. It makes no sense to use the entire JDK when only a part or a small part of it is needed. The Compact Profiles introduced in Java 8 recognized the problems caused by the huge JDK and attempted to solve them, but only to a low degree. The three Compact Profiles still contain a lot of libraries that a developer may not actually need. There had to be a better way to split the entire JDK and to create a much smaller custom JDK as a runtime image that contains only the libraries needed and nothing more. Project Jigsaw is that way, as we’ll see throughout this book.
Big, monolithic software applications present a series of disadvantages. Maintaining them is tough and expensive, and performing a small change can result into a great effort. In large projects, modularity is crucial because it allows easy maintenance of the source code by reducing its complexity due to the loose coupling mechanism it provides.
The problems related to class path have been in Java since the birth of the language. The Java Virtual Machine (JVM) doesn’t know that a JAR on the class path depends on another JAR. It simply loads a group of JARs, but it doesn’t check their dependencies. When a JAR is missing, the JVM breaks the execution at runtime. The JARs can’t define concepts related to accessibility. They don’t define accessibility constraints like public or private. The entire content of all JARs on the class path is completely visible to all the other JARs from the class path. There’s no way to declare that some classes in a JAR are private. All classes and methods are public related to the class path, which leads to a problem sometimes called JAR hell . Conflicts between versions of JARs can arise, especially when two different versions of the same library are required. Loading the classes from the class path is a slow process because the JVM doesn’t know where exactly the class is located and therefore has to check all the existing files from the class path. Jigsaw addresses this pain point. By taking advantage of reliable configuration, module boundaries are enforced, and the JVM knows about the dependencies that are needed. This has a positive impact on performance. Java 9 defines the concept of module path and allows you to have a library as a JAR file on the class path or have the same library as a module on the module path. This means nobody is forced to turn all their libraries into modules when they switch to Java 9. The libraries can still be used on the class path, even in Java 9. This is a big advantage because Java 9 provides a smooth transition of libraries.
The module path introduced in Java 9 tends to solve the problems caused by the class path. It can replace the class path completely or can interact and work together with the class path.
Modularity is important because it provides a maintainable code base for the future. We should use modular programming when we want to separate the effort put into design, development, and testing. Modular programming speeds up development and makes debugging applications easier by reducing their complexity.
The first chapter of this book describes the concepts that build the foundation of a modular application: high module cohesion, strong encapsulation, low module coupling and explicit interfaces. It also illustrates some of the most important principles of modular programming, like: continuity, understandability, reusability, combinability, and decomposability.
You may wonder why we shouldn’t use OSGi instead of Jigsaw. The reason is that OSGi can’t be used to modularize the JDK because it’s built on top of the Java Development Kit Platform. Jigsaw isn’t built on top of the platform but rather directly into the core of it . This allows Jigsaw to completely change the structure of the JDK. The main differences between Jigsaw and OSGi are described in Chapter 2 .
Prior to JDK 9, there was no way to manage modules. That’s where Project Jigsaw comes into action. It introduces a brand new modular system into the JDK and therefore allows applications to be built on the skeleton of a modular architecture. It brings flexibility, maintainability, security, and scalability to the Java platform. It introduces loosely coupled modules by clearly defining the dependencies between the modules.
Project Jigsaw groups the source code of the Java platform into modules and provides a new system to implement modules as part of the platform. It applies the modular system to the platform and to the JDK itself and offers programmers the possibility of writing programs using the modular system on top of the JDK.
The main goal of Project Jigsaw is to modularize the JDK and the runtime. A new component called module is introduced. Chapter 4 explains what a module is and how to define a module in Java 9. That chapter also examines how to declare a module’s dependencies, how to encapsulate, and how to hide a module’s internal implementation. You’ll learn what an unnamed module, a named module, an automatic module, and an open module are. The chapter introduces the notion of module path and shows how to build a module graph with no cycles.
Regarding modules declarations, I show practical examples using each of the five clauses introduced in Jigsaw: the requires clause, the exports clause, the uses clause, the provides clause, and the opens clause.
The objective of the Java modular system is to provide strong encapsulation and reliable configuration . Chapter 2 explains what these notions mean and how they’re achieved through the modular system in Java 9.
The class path is partially replaced by modules and the module path. The class path–specific well-known ClassNotFound exceptions are avoided on the module path because the compiler can now test, based on the modules’ definitions, whether all the modules needed to run the application are available. If they’re not found, it doesn’t compile the application.
Accessibility is an important part of the entire ecosystem and is covered throughout this book. The integral concept regarding the manner in which accessibility is achieved fundamentally changes in Java 9. The public access identifier that we all know no longer means accessible everywhere and to anyone . Supplementary accessibility levels have been added in JDK 9 that extend the existing accessibility mechanism by defining accessibility at the module level. Concepts like direct and implied readability , prerequisites for defining accessibility, are also outlined in this book. You’ll see how accessibility is imposed by the compiler, by the virtual machine, or by using core reflection.
We’ll look at the new concept of modular JAR files and the great advantage it brings: the possibility of compiling a library with JDK 9+, using it on the module path for JDK 9+, and compiling it with JDK8 or earlier and using it on the class path. Because the class path can still be used, the migration of libraries to JDK 9 is smooth. Even if the libraries contain a module descriptor and are to be treated as “modules,” they will still work on previous versions of JDK 9 because their module descriptor won’t be taken into consideration on the class path. By using modular JARs, developers have the freedom to decide whether they want to switch to the module platform or not.
We’ll highlight the distinctions between regular and modular JARs with some examples and describe the new format for files introduced in Java 9, called JMOD, which is very similar to the format of JAR files. We’ll go over the new JMOD tool and describe its use in detail.
The compilation of multiple modules using the --module-source-path option is illustrated with some explanatory examples. We’ll also describe the enhancements added to the jar tool and show how to use it to package everything as a modular JAR or as a JMOD file.
We’ll see how to run the compiled classes and the module-info.class using the java launcher. New options like --module-path and -m , introduced in JDK9, are covered thoroughly. When attempting to run an application using the -m option, which tells the launcher where the main module is, a resolution is triggered. We’ll describe in detail all the steps involved when running a Java modular application, including resolution triggering and generation of the module graph. We’ll also look at special cases like when a module is missing and the startup fails, and we’ll present some workarounds for this, such as using the newly introduced java launcher option --show-module-resolution .
We’ll also put modular JARs on the class path and see how to successfully run them. This is very important: We’ll explain how to mix the class path and the module path when running with the java launcher. For this, we’ll take advantage of the newly introduced --add-modules command-line option.
Chapter 3 describes the JEP 200, called the Modular JDK. This is the JEP that splits the JDK into a set of modules. We’ll consider the new structure of the JDK together with its modules. We’ll talk about platform modules and show the module graph that represents the new modular structure of the JDK. We’ll examine the graph, show how modules depend on each other, and learn how to list all the modules from the system using the --list-modules command-line option. We’ll also explain the notions of standard module and non-standard module.
It’s beyond the scope of this book to go through every module in detail. You can find a comprehensive list of all the existing modules on the Open JDK website at http://cr.openjdk.java.net/∼mr/jigsaw/ea/module-summary.html .
The JEP 260, Encapsulate most internal APIs, is also covered in this book. In order to manage incompatibilities, all non-critical internal APIs were encapsulated by default. Besides that, all critical internal APIs for which supported replacements exist in JDK 8 were encapsulated. Other critical internal APIs weren’t encapsulated. Since they were deprecated in JDK 9, a workaround via a command-line flag is provided.
A linker and a new phase called link-time were introduced in Java 9. This phase is optional and is executed after the compile-time but before the runtime. It basically assembles the modules in order to form a runtime image. Runtime images allow us to create custom JDKs that contain only the minimum number of modules necessary to run our application. The minimum possible runtime would contain a single module, the java.base module. Runtime images allow us to scale down the JDK or to scale it up based on our needs. They’re a replacement of the runtime rt.jar.
The linker represents a new phase of the development life-cycle. It improves performance by selecting only the minimum modules that it needs to successfully compile the code and provides many optimization options for the future.
Jigsaw makes it possible to install separate modules as part of the JDK platform installation. It also allows us to dynamically include other additional modules in the JDK runtime image. We’ll talk about the changes related to the binary structure of the JRE and the JDK and about the new structure of the legacy JDK image. You’ll learn more about all these new concepts in Chapters 5 and 7 .
In Chapter 6 you’ll learn what services are, and we’ll describe through examples the notions of service interface and service providers. We’ll show how to define service providers in modules and how to make them available to other modules.
In Chapter 8 you’ll see how to migrate applications and libraries to modules in a smooth way. We’ll describe how to migrate an application to Java 9 using the top-down migration strategy. For this, we’ll look at a concrete example of how to migrate an application that contains some third-party JARs to modules. We’ll see which kind of applications present the risk of breaking when switching to JDK 9. We’ll will give useful solutions to avoid this, such as searching the code for dependencies, avoiding splitting packages, and checking the usage of the internal APIs. If you’ve already switched to JDK 9, we recommend trying first to run your applications with the new JDK to see if it breaks your code. We’ll cover the JDeps tool and how to use it to audit your code and search for JDK-internal APIs. We’ll discuss the Maven JDeps plugin, which represents the integration of the JDeps tool with the build tool Maven. We’ll also talk about the impact and consequences of the removal of rt.jar and tools.jar from the JRE.
Chapter 9 covers the new API introduced in JDK 9 for working with modules. We’ll see how to perform basic operations on modules.
Chapter 10 gets into some advanced topics like layers, class loading mechanism in JDK 9, multi-release JAR files, the JMOD tool, and upgradeable modules. We’ll describe the concept of layers, which are a group of class loaders used to load classes from a module graph. We’ll look at the boot layer and the correlation to the so-called well-formed graphs.
Chapter 11 talks about how to handle different scenarios for testing modular applications. Three scenarios are covered: Junit test classes and objects under test residing in different modules, Junit test classes and objects under test residing in the same module, and only objects under test residing inside a module. We’ll show how to patch a module and how to use Maven for easing testing.
In Chapter 12 you’ll learn how Jigsaw interacts with build tools like Maven and what kind of support the most popular IDEs offer for Project Jigsaw.
As you can see, this book is structured into 12 chapters. Chapter 1 covers modular programming concepts. Chapters 2 – 9 provide you with a very strong foundation on Project Jigsaw. Chapter 10 describes some advanced features that will help you understand some complex topics on Jigsaw. Chapter 11 shows how to test modular applications using Junit. Chapter 12 teaches using Jigsaw together with build tools and integrated development environments (IDEs).
Each topic should be easy to find. We recommend reading the chapters sequentially in order to understand all the topics. Some examples build on concepts that were explained in previous chapters.
This book is intended for anyone who wants to get familiar with the new modularity system introduced in Java 9. It gives a strong foundation for anyone who wants to understand the core concepts as well as the advanced concepts of Java 9 modularity. The examples are designed to help you deeply understand all the notions introduced in Project Jigsaw. We’ve tried, as much as possible, to give a plenty of examples for most of the theoretical concepts discussed throughout the book.
Whether you already have experience with modular systems or not, this book is for you.
The book can’t cover everything on Java 9 modularity. Java 9 modularity is a very large and complex subject, and covering every corner of it wouldn’t be possible in a book of this size. However, the book goes through all the core parts of Java 9 modularity and touches some advanced topics. By reading this book, you’ll not only understand the concepts behind Java 9 modularity, you’ll also be able to apply them on your day-by-day projects.
We advise you to try the examples from this book by yourself in order to get familiar with Project Jigsaw.
This book aims to provide comprehensive information on the new modular system introduced in Java 9. A well-structured tutorial is conducted throughout the book by combining theoretical concepts with practical examples.
Learning to use modularity with Java 9 will help you enhance your technology career and give you very precious technical skills.
Once you read this book, you’ll be able to develop scalable and modular Java 9 applications and migrate existing Java applications to Java 9.
Here are some of the most important things you’ll learn in this book:
What modularity is in general and what advantages it brings
What Java 9 modularity is and what its goals are
How the new layout for JDK and JRE looks
What strong encapsulation and reliable configuration are and how to apply and take advantage of them
Which JDK-internal APIs have been encapsulated in Java 9 and which have remained accessible
How the JDK was divided into a group of modules
What the new accessibility rules in JDK 9 are
How to define a module together with its dependencies
How to create a modular JAR file and a JMOD file
How to compile, package, and run a modular Java application using Jigsaw
How to use the JDeps tool to audit the code, search for dependencies between the libraries, or generate module descriptors
How to migrate an application to the modular system
How to solve migration issues like encapsulated JDK internal APIs, not resolved modules, split packages, cyclic dependencies, and more
How to perform top-down migration
How to define, configure, and use services for modules
How to combine the module path and the class path to provide backward compatibility
How to create custom modular runtime images using the Jlink linking tool
How to define and use a layer in Java 9
How to perform operations on a Module using the new Module API
How to use qualified exports
How to improve the maintainability and performance of Java applications
How to handle the unit testing of a modular application
How to patch a module
How to integrate Jigsaw with different build tools like Maven
How to check whether a Java application is compatible with JDK 9
How to make a Java application compatible with JDK 9
How to assure runtime compatibility when switching to Java 9
How to choose the best design patterns when modularizing a Java application
Everybody involved in publishing this book is strongly committed to providing an error-free book. That’s why the errata of this book is continuously updated as soon as even a minor issue is found. You can submit errata at www.apress.com/us/services/errata .
The source code for this book can be accessed by clicking the Download Source Code button on its apress.com product page, located at www.apress.com/9781484227121 .
The source code from this book can be found on GitHub. You can also download it from the book’s product page at www.apress.com/us/book/9781484227121 .
I would like to thank my family and my wife, Diana, for supporting me, encouraging me, and understanding me during the long nights and weekends spent on writing on this book.
I would like to thank my parents, Alexandrina and Eugen, for providing me with a very good education since I was a young child. Thank you for investing in my education and for providing me computer science and foreign languages courses since my first years . Thank you for raising me very well.
I would like to thank the entire team at Apress for their very good and professional work. Thanks to my coordinating editor, Jill Balzano, and my acquisitions editor, Jonathan Gennick, for trusting me and guiding me with precious advice and support through the difficult journey of writing this book. I also thank you for your patience and for encouraging me throughout the entire writing process. I thank my technical reviewer, Josh Juneau, for providing me with very helpful and useful reviews. Thank you, Apress team, for the excellent work!
—Alexandru Jecan
Alexandru Jecan is a senior software engineer, consultant, author, trainer, speaker and tech entrepreneur currently residing in Munich, Germany. He earned a degree in computer science from the Technical University of Cluj-Napoca, Romania.
Alexandru provides professional in-house trainings on various software technologies across Germany. His areas of specialization are: big data, data analysis, artificial intelligence, machine learning, back-end software development, front-end software development, database development, microservices and devops.
He speaks at tech conferences and user groups, both in Europe and the United States, on different topics related to software development and software technologies.
In his free time, Alexandru likes to read a lot and to spend time with his family. Alexandru is an avid reader, reading lots of books and magazines in the fields of information technology, economy, business and stock markets. He also reads Hacker News frequently and is delighted with how many extraordinary, outstanding and very smart people are on this planet. You can follow Alexandru on Twitter at @alexandrujecan, read his tech blog at www.alexandrujecan.com , or email him at [email protected].
Josh Juneau has been developing software and enterprise applications since the early days of Java EE. Application and database development have been his focus since the start of his career. He became an Oracle database administrator and adopted the PL/SQL language for performing administrative tasks and developing applications for the Oracle database. In an effort to build more complex solutions, he began to incorporate Java into his PL/SQL applications and later developed standalone and web applications with Java. Josh wrote his early Java web applications utilizing JDBC and servlets or JSP to work with backend databases. Later, he began to incorporate frameworks into his enterprise solutions, such as Java EE and JBoss Seam. Today, he primarily develops enterprise web solutions utilizing Java EE and other technologies. He also includes the use of alternative languages, such as Jython and Groovy, in some of his projects.
Over the years, Josh has dabbled in many different programming languages, including alternative languages for the JVM, in particular. In 2006, Josh began devoting time to the Jython Project as editor and publisher of the Jython Monthly newsletter. In late 2008, he began a podcast dedicated to the Jython programming language. Josh was the lead author for The Definitive Guide to Jython , Oracle PL/SQL Recipes , and Java 7 Recipes , and a solo author of Java EE 7 Recipes and Introducing Java EE 7 —all published by Apress. He works as an application developer and system analyst at Fermi National Accelerator Laboratory and writes technical articles for Oracle and OTN. He was a member of the JSR 372 and JSR 378 expert groups and is an active member of the Java community, helping to lead the Chicago Java User Group’s Adopt-a-JSR effort.
When not coding or writing, Josh enjoys spending time with his wonderful wife and five children, especially swimming, fishing, playing ball, and watching movies. To hear more from Josh, follow his blog at http://jj-blogger.blogspot.com . You can also follow him on Twitter at @javajuneau.
3.137.217.198