Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

The Java Module System: reliably configuring Java 9 modules

1,581 views

Published on

Java's much-awaited "Project Jigsaw" is finally here! Java 9 will include a built-in modularity framework, and The Java Module System is your guide to discovering it.

Save 42% off The Java Module System with code slparlog at: https://www.manning.com/books/the-java-9-module-system

Published in: Software
  • Be the first to comment

The Java Module System: reliably configuring Java 9 modules

  1. 1. Save 42% off The Java Module System by Nicolai Parlog with code slparlog at manning.com
  2. 2. Connecting the pieces Modules are the atomic building blocks, the nodes in our graph of interacting artifacts. But there can be no graph without edges connecting the nodes! So the modules express which other modules they depend on, creating edges between them. The next slide shows a graphic of the types of JVM modules: Need some background info on Java 9 modules? Check out the author’s website: http://blog.codefx.org/tag/jpms/
  3. 3. Observable Unnamed Named Platform Application Automatic Base Initial Types of modules
  4. 4. Let’s imagine that we have a module customer and a module bar. When a module customer requires module bar in its declaration, then at run time customer will read bar or, conversely, bar will be readable by customer. barcustomer 1. requires bar 2. reads
  5. 5. With that in mind, you can see how phrases like "customer requires bar" and "customer depend on bar“ mirror a static, compile-time relationship between customer and bar; readability is the more dynamic, run-time counterpart. You might be asking: Why is it more dynamic? While the requires clause is the primal originator of readability edges, it is by no means the only one – both command line arguments and the reflection API can be used to add more. However they came to be, readability edges are the basis for reliable configuration and strong encapsulation.
  6. 6. Achieving reliable configuration Reliable configuration aims to ensure that the particular configuration of artifacts a Java program is compiled against, or launched with, can sustain the program without spurious run-time errors. To this end it performs a couple of checks – which happen during module resolution. The next slide shows the verification sequence.
  7. 7. 1. First and foremost, the module system checks whether the universe of observable modules contains all required dependencies (both direct and transitive) and reports an error if something is missing. 2. There must be no ambiguity, which means that no two artifacts can claim that they are the same module. This is particularly interesting in the case where two versions of the same module are present—unfortunately the module system has no concept of versions and thus treats this as a duplicate module. Accordingly, you get an error if it runs into this situation. 3. There must be no static dependency cycles between modules. At run time it is possible and even necessary for modules to access each other, but these must not be compile dependencies. 4. Packages should have a unique origin so no two modules contain types in the same package. If they do, this is called a split package and the module system will refuse to compile or launch such configurations.
  8. 8. This verification is, of course, not airtight and it is still possible for problems to hide long enough to crash a running application. If, for example, the wrong version of a module ends up in the right place, then the application will still launch (all required modules are present after all) but crash later when, for example, a class or method is missing. The module system is developed to exhibit consistent behavior across compile and run time, though, so these errors can be further minimized if it can be guaranteed that compilation and launch are based on the same artifacts (for example, a compilation against a module with the wrong version would fail).
  9. 9. Unreliable configurations Now that you know how the module system is supposed to work (and when it won’t), let’s see if we can break things – so you know what to do when things go wrong (they will). Imagine that we have a simple monitor application, and consider monitor.observer.alpha and its declaration: module monitor.observer.alpha { requires monitor.observer; exports monitor.observer.alpha; }
  10. 10. Missing dependencies Now let’s see what it would look like to try to compile it with monitor.observer missing: Missing dependency, no compilation! monitor.observer.alpha/src/main/java/module-info:2: error: module not found: monitor.observer requires monitor.observer ^ 1 error
  11. 11. A different error would get thrown if the module was present at compile time, but got lost on the way to the launch pad. In this instance, the JVM will quit with the following: Missing dependencies Error occurred during initialization of VM java.lang.module.ResolutionException: Module monitor.observer not found, required by monitor.observer.alpha
  12. 12. Duplicate modules Since modules reference one another by name, any situation where two modules claim to have the same name is ambiguous. Which one is the correct one to pick is highly dependent on the context and not something the module system can generally decide. So, instead of making a potentially bad decision, it makes none at all and instead produces an error. This commitment to failing fast allows the developer to notice a problem and fix it before it causes any more problems.
  13. 13. Duplicate modules This is the compile error the module system produces when trying to compile a module with two variants of monitor.observer.beta on the module path: The compiler cannot link the error to one of the files under compilation because they are not the reason for the problem. In this case, the artifacts on the module path are causing the error. error: duplicate module on application module path module in monitor.observer.beta 1 error
  14. 14. Duplicate modules In the event of an error going undetected until the JVM is launched, we get a more precise message that lists the JAR file names as well: As we mentioned before, the module system has no concept of versions – many errors can be traced to having several versions of the same module on the module path. Error occurred during initialization of VM java.lang.module.ResolutionException: Two versions of module monitor.observer.beta found in mods (monitor.observer.beta.jar and monitor.observer.gamma.jar)
  15. 15. Dependency cycles Getting dependency cycles through the compiler takes some doing, and, if not done properly, will result in a compile error. This is how it looks if monitor.persistence and monitor.statistics depend on each other: monitor.statistics/src/main/java/module-info:3: error: cyclic dependence involving monitor.persistence requires monitor.persistence; ^ 1 error
  16. 16. Split packages A split package occurs when two modules contain types in the same package. For example, the monitor.statistics module contains a class Statistician in the monitor.statistics package. Now let’s assume the monitor module contained a very simple fallback implementation SimpleStatistician, and to promote uniformity, the monitor module has placed it in its own monitor.statistics package. The error we would get at compile time is on the next slide:
  17. 17. Split packages Interestingly enough, the compiler only shows an error if the module under compilation can access the split package in the other module, which means the split package must be exported. monitor/src/main/java/monitor/statistics/SimpleStatistician.java:1: error: package exists in another module: monitor.statistics package monitor.statistics; ^ 1 error
  18. 18. Split packages Let’s see this another way: SimpleStatistician is gone and this time monitor.statistics creates the split module. It gets a Utils class in the monitor package, and continues to only export the monitor.statistics package. Compiling monitor.statistics is error-free, which makes sense because it does not require monitor. Compiling monitor is more interesting because it depends on monitor.statistics and both contain types in the package monitor. But because monitor.statistics does not export the split package, compilation is successful.
  19. 19. Split packages That didn’t go so well… Indeed, the module system checks for split packages on launch and here it doesn’t matter whether they are exported or not: There can be no two modules that contain types in the same package. Error occurred during initialization of boot layer java.lang.reflect.LayerInstantiationException: Package monitor in both module monitor.statistics and module monitor Let’s see what happens when we launch:
  20. 20. Grab your copy of The Java Module System and save 42% with code slparlog at manning.com. Also see:

×