This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sis-site.git

commit 768e4fa06bacb44c528fda68b81d1a1ee4cca5d0
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Oct 2 17:36:51 2023 +0200

    Add notes about Java modules in SIS 1.4 and later.
---
 content/_index.md                        |   5 +-
 content/downloads.md                     |  49 +-
 content/release-notes/_index.md          |   5 +
 content/source.md                        |   2 +
 static/release-notes/Modularization.html | 891 +++++++++++++++++++++++++++++++
 5 files changed, 937 insertions(+), 15 deletions(-)

diff --git a/content/_index.md b/content/_index.md
index d6461524..a078a877 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -61,9 +61,12 @@ The API and the data encodings follow [international 
standards](standards.html)
 
 The latest SIS release is {{% version %}}, released in October 2023,
 and can be [downloaded](downloads.html) as a `zip` files or as Maven 
dependencies.
-This version requires Java 11 or later.
 The EPSG geodetic dataset is optional for licensing reasons, but recommended.
 EPSG database installation is [described in a separated page](epsg.html).
+This Apache SIS version requires Java 11 or later and uses the Java Platform 
Module System (JPMS).
+Consequently applications should declare SIS JAR files on their module-path 
rather than their class-path,
+but a compatibility mechanism makes possible to nevertheless use SIS on the 
class-path.
+Note that this class-path compatibility may be removed in future versions.
 
 Apache {{% SIS %}} is a Java library for use by other applications.
 Leveraging the full SIS capabilities or getting the best performance require 
that users write their own applications on top of SIS.
diff --git a/content/downloads.md b/content/downloads.md
index 5b753b8a..b089844c 100644
--- a/content/downloads.md
+++ b/content/downloads.md
@@ -11,6 +11,7 @@ See the `NOTICE` file contained in each release artifact for 
applicable copyrigh
 
 {{< toc >}}
 
+
 # Download ZIP files    {#bundles}
 
 Apache {{% SIS %}} is distributed in the form of Java source code in a 
multi-modules Apache Maven project.
@@ -22,6 +23,7 @@ Optional dependencies (JAXB implementation, UCAR netCDF 
library, Amazon SDK) are
 * [Apache SIS {{% version %}} javadoc][doc] \[[PGP][doc-PGP]\] \[[SHA 
512][doc-SHA]\]
 * [Apache SIS {{% version %}} sources][src] \[[PGP][src-PGP]\] \[[SHA 
512][src-SHA]\] ([build instruction](build.html))
 
+
 ## Verify signatures    {#release-gpg}
 
 All downloads can be verified using the Apache {{% SIS %}} code signing 
[KEYS][keys].
@@ -51,6 +53,25 @@ pgpk -a KEYS
 pgpv apache-sis-{{% version %}}-src.zip.asc
 {{< / highlight >}}
 
+
+## Setting the module-path
+
+Apache SIS 1.4 and later use the Java Platform Module System (JPMS).
+Consequently applications should declare SIS JAR files on their module-path 
rather than their class-path.
+The easiest way is to declare the whole directory like below:
+
+{{< highlight bash >}}
+java --module-path apache-sis-{{% version %}}/lib
+{{< / highlight >}}
+
+If the application using Apache SIS is not itself modularized,
+it may be necessary to add the `--add-modules ALL-MODULE-PATH` option.
+If it is not possible to declare SIS JAR files on the module-path,
+a compatibility mechanism makes possible to nevertheless use SIS {{% version 
%}} on the class-path.
+Note however that declaring SIS JAR files on the class-path may be no longer 
supported in a future version
+(it does **not** mean that applications using SIS must put themselves on the 
module-path).
+
+
 # Download as Maven dependencies    {#maven}
 
 An easy approach to integrate Apache {{% SIS %}} into a Java project uses the 
[Apache Maven][maven]
@@ -82,20 +103,20 @@ Below are examples of declarations in a `pom.xml` file for 
building a project wi
 The `sis-referencing` module in above example can be replaced by one or many 
of the following modules:
 
 <table>
-  <tr><th>Service</th>                          <th>Group</th>                 
                  <th>Artifact</th></tr>
-  <tr><td>ISO 19115 metadata</td>               
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-metadata</code></td></tr>
-  <tr><td>Referencing by coordinates</td>       
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-referencing</code></td></tr>
-  <tr><td>Referencing by identifiers</td>       
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-referencing-by-identifiers</code></td></tr>
-  <tr><td>Features and coverages</td>           
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-feature</code></td></tr>
-  <tr><td>Feature data from SQL database</td>   
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-sqlstore</code></td></tr>
-  <tr><td>Feature data from GPX files</td>      
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-xmlstore</code></td></tr>
-  <tr><td>Features and rasters from NetCDF</td> 
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-netcdf</code></td></tr>
-  <tr><td>Raster data from GeoTIFF</td>         
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-geotiff</code></td></tr>
-  <tr><td>Raster data from Landsat</td>         
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-earth-observation</code></td></tr>
-  <tr><td>Raster data from GCOM (JAXA)</td>     
<td><code>org.apache.sis.profile</code></td>     
<td><code>sis-japan-profile</code></td></tr>
-  <tr><td>Connection to storages on cloud</td>  
<td><code>org.apache.sis.cloud</code></td>       
<td><code>sis-cloud-aws</code></td></tr>
-  <tr><td>Console application</td>              
<td><code>org.apache.sis.application</code></td> 
<td><code>sis-console</code></td></tr>
-  <tr><td>Graphical application</td>            
<td><code>org.apache.sis.application</code></td> 
<td><code>sis-javafx</code></td></tr>
+  <tr><th>Service</th>                          <th>Java module name</th>      
                               <th>Maven group</th>                             
<th>Maven artifact</th></tr>
+  <tr><td>ISO 19115 metadata</td>               
<td><code>org.apache.sis.metadata</code></td>                 
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-metadata</code></td></tr>
+  <tr><td>Referencing by coordinates</td>       
<td><code>org.apache.sis.referencing</code></td>              
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-referencing</code></td></tr>
+  <tr><td>Referencing by identifiers</td>       
<td><code>org.apache.sis.referencing.gazetteer</code></td>    
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-referencing-by-identifiers</code></td></tr>
+  <tr><td>Features and coverages</td>           
<td><code>org.apache.sis.feature</code></td>                  
<td><code>org.apache.sis.core</code></td>        
<td><code>sis-feature</code></td></tr>
+  <tr><td>Feature data from SQL database</td>   
<td><code>org.apache.sis.storage.sql</code></td>              
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-sqlstore</code></td></tr>
+  <tr><td>Feature data from GPX files</td>      
<td><code>org.apache.sis.storage.xml</code></td>              
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-xmlstore</code></td></tr>
+  <tr><td>Features and rasters from NetCDF</td> 
<td><code>org.apache.sis.storage.netcdf</code></td>           
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-netcdf</code></td></tr>
+  <tr><td>Raster data from GeoTIFF</td>         
<td><code>org.apache.sis.storage.geotiff</code></td>          
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-geotiff</code></td></tr>
+  <tr><td>Raster data from Landsat</td>         
<td><code>org.apache.sis.storage.earthobservation</code></td> 
<td><code>org.apache.sis.storage</code></td>     
<td><code>sis-earth-observation</code></td></tr>
+  <tr><td>Raster data from GCOM (JAXA)</td>     
<td><code>org.apache.sis.profile.japan</code></td>            
<td><code>org.apache.sis.profile</code></td>     
<td><code>sis-japan-profile</code></td></tr>
+  <tr><td>Connection to storages on cloud</td>  
<td><code>org.apache.sis.cloud.aws</code></td>                
<td><code>org.apache.sis.cloud</code></td>       
<td><code>sis-cloud-aws</code></td></tr>
+  <tr><td>Console application</td>              
<td><code>org.apache.sis.console</code></td>                  
<td><code>org.apache.sis.application</code></td> 
<td><code>sis-console</code></td></tr>
+  <tr><td>Graphical application</td>            
<td><code>org.apache.sis.gui</code></td>                      
<td><code>org.apache.sis.application</code></td> 
<td><code>sis-javafx</code></td></tr>
 </table>
 
 
diff --git a/content/release-notes/_index.md b/content/release-notes/_index.md
index 20689f50..e93f31a5 100644
--- a/content/release-notes/_index.md
+++ b/content/release-notes/_index.md
@@ -3,3 +3,8 @@ title: Release notes
 ---
 
 For latest version, see [SIS {{% version %}} release notes]({{% version 
%}}.html).
+
+
+# Annexes    {#annexes}
+
+* [Java Module Source Hierarchy in Apache SIS](Modularization.html)
diff --git a/content/source.md b/content/source.md
index 42b00181..be082f97 100644
--- a/content/source.md
+++ b/content/source.md
@@ -221,6 +221,8 @@ after {{% OGC %}} releases the corresponding GeoAPI 
versions.
 
 # History    {#history}
 
+The build system before Apache {{% SIS %}} 1.4 was Maven.
+Migration to Gradle was necessary for partial support of Module Source 
Hierarchy.
 All developments and tags prior Apache {{% SIS %}} 1.0 were done on a 
[Subversion][subversion] repository
 and can be [browsed online][viewvc].
 Tags for Apache {{% SIS %}} versions 0.1 to 0.8 should be fetched from the 
[SVN repository][svn-sis-tags].
diff --git a/static/release-notes/Modularization.html 
b/static/release-notes/Modularization.html
new file mode 100644
index 00000000..7e6e93f2
--- /dev/null
+++ b/static/release-notes/Modularization.html
@@ -0,0 +1,891 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Java Module Source Hierarchy in Apache SIS</title>
+    <meta charset="UTF-8">
+    <style>
+      h2 {
+        border-top: solid;
+        border-width: 6px;
+        border-color: DarkTurquoise;
+        margin-top:  80px;
+        padding-top: 80px;
+      }
+      h3 {
+        margin-top:   48px;
+        margin-bottom: 9px;
+      }
+      h4 {
+        margin-top:   32px;
+        margin-bottom: 9px;
+      }
+      p {
+        text-align: justify;
+        font-size:  16px;
+      }
+      blockquote, li {
+        font-size: 16px;
+      }
+      pre {
+        font-size: 14px;
+      }
+      pre.snippet {
+        padding:      20px;
+        margin-left:  80px;
+        margin-right: 80px;
+        border-style: solid;
+        border-width: 1px;
+        border-color: gray;
+        background:   #F8F8F8;
+      }
+      pre.tree {
+        font-size:   18px;
+        line-height: 100%;
+        color: gray;
+      }
+      pre.tree span.plain, pre.tree span.del, pre.tree span.new, pre.tree 
span.use, pre.tree span.note {
+        font-size: 14px;
+      }
+      pre.tree span.del, pre.tree span.new, pre.tree span.use  {
+        font-weight: bold
+      }
+      span.plain {color: black}
+      span.new   {color: SteelBlue}
+      span.del   {color: red}
+      span.use   {color: green}
+      span.note  {font-family: serif; font-style: italic}
+      span.string {color: DarkGoldenRod}
+
+      table.two-columns {
+        margin-left:  auto;
+        margin-right: auto;
+        border-style: solid;
+        border-width: 3px;
+        background: #F8F8F8;
+      }
+      table.two-columns tr {
+        vertical-align: top;
+      }
+      table.two-columns td {
+        padding-left:   20px;
+        padding-right: 130px;
+      }
+      table.two-columns th.next, table.two-columns td.next {
+        border-left: 3px solid;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Java <i>Module Source Hierarchy</i> in Apache <abbr>SIS</abbr></h1>
+    <p><b>Annex to <a href="1.4.html">Apache <abbr title="Spatial Information 
System">SIS</abbr> 1.4 release notes</a>, October 2023</b></p>
+    <p>
+      Since the release of Java 9 and the Java Platform Module System 
(<abbr>JPMS</abbr>, code-named "Jigsaw"),
+      the tendency in Maven or Gradle projects is to either ignore 
<abbr>JPMS</abbr>,
+      or to consider Java modules as equivalent to Maven modules or Gradle 
sub-projects:
+      each Maven module contains exactly one Java module,
+      and the same convention is applied to Gradle sub-projects.
+      This restriction is inherited from Java 8 days,
+      when the Java compiler accepted only a directory layout named <i>Package 
Hierarchy</i>
+      (directory names match exactly package names).
+      Few peoples are aware that since Java 9, most Java tools,
+      such as <code>javac</code> and <code>javadoc</code>,
+      accept an alternative layout named <i>Module Hierarchy</i>
+      (source: <code>javac</code> <a 
href="https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#directory-hierarchies";>Directory
 Hierarchies</a>).
+      The latter is used for example by the OpenJDK project itself.
+    </p><p>
+      Since Java 9, the <code>javac</code> and <code>javadoc</code> tools can 
process
+      many <abbr title="Java Platform Module System">JPMS</abbr> modules 
together.
+      Allowing that multiplicity in developer's project has some advantages 
described in this page.
+      To summarize, it gives to developers an extra level of flexibility for 
organizing their modules,
+      enables more compile-time checks of cross-module documentation,
+      facilitates aggregated javadoc and aggregated annotation processing,
+      facilitates the reuse of test fixtures between modules, and more.
+      However taking full advantage of <abbr title="Java Platform Module 
System">JPMS</abbr>
+      requires changes in the directory layout compared to Maven and Gradle 
conventions.
+      As of October 2023, both Maven and Gradle support only the directory 
layout known as <i>Package Hierarchy</i>.
+      This page describes how the alternative <i>Module Source Hierarchy</i>
+      can be applied to the <a href="https://sis.apache.org/";>Apache SIS</a> 
project.
+      The layout described below is currently very difficult to apply with 
Maven,
+      so a migration from Maven to Gradle was necessary.
+    </p><p>
+      <b>Table of content:</b>
+    </p>
+    <ul>
+      <li><a href="#overview">Overview of directory layout change</a></li>
+      <li><a href="#restructuring">Apache SIS restructuring</a></li>
+      <li><a href="#gradle-config">Gradle configuration for Module Source 
Hierarchy</a>
+        <ul>
+          <li><a href="#gradle-issues">Gradle issues and workarounds</a></li>
+        </ul>
+      </li>
+      <li><a href="#advantages">Advantages of Source Module Hierarchy</a></li>
+      <li><a href="#limitations">Limitations of Source Module 
Hierarchy</a></li>
+      <li><a href="#maven-bug">Quasi-blocker Maven bug</a></li>
+      <li><a href="#conclusion">Conclusion</a>
+        <ul>
+          <li><a href="#gradle-proposals">Ideas for Gradle evolution</a></li>
+          <li><a href="#links">Links to issues and test cases</a></li>
+        </ul>
+      </li>
+    </ul>
+
+    <h2 id="overview">1) Overview of directory layout change</h2>
+    <p>
+      Multiple Java modules in a single Gradle sub-project does not mean that 
Gradle sub-projects should be abandoned.
+      Instead, Java modules introduces one new level of sub-division between 
Gradle sub-projects and Java packages,
+      illustrated by the blue line below. Developers should be free to use it 
or not,
+      and to choose what to group as a Gradle sub-project and what to group as 
a Java module.
+    </p>
+    <ol>
+      <li>A Gradle project can be (if desired) a tree of Gradle 
sub-projects.</li>
+      <li><span class="new">Each Gradle leaf sub-project can contain many Java 
modules.</span></li>
+      <li>Each Java module can contain many Java packages.</li>
+    </ol>
+    <p>
+      Java provides some flexibility about the directory layout in a Module 
Source Hierarchy.
+      In this section, we assume that the developer wants to stay close to 
Maven conventions.
+      The <span class="use">names in green</span> are directories taken 
unchanged from Maven conventions
+      and <span class="new">names in blue</span> are new directories added for 
Module Source Hierarchy support.
+      The <span class="del">names in red</span> are directories from Maven 
conventions that we dropped in <abbr>SIS</abbr> 1.4,
+      but this is specific to Apache <abbr title="Spatial Information 
System">SIS</abbr> restructuring and does not need
+      to be adopted for other projects (the <code>java</code> directory 
relevance is a separated debate).
+      In the figure below, the paths on the left side can become the paths on 
the right side,
+      where <span class="new"><var>&lt;module&gt;</var></span> shall be 
replaced by a
+      <abbr title="Java Platform Module System">JPMS</abbr> module name
+      such as <span class="new"><code>org.apache.sis.storage</code></span>.
+    </p>
+    <table class="two-columns">
+      <tr>
+        <th>Current Maven layout</th>
+        <th class="next">Module Source Hierarchy</th>
+      </tr>
+      <tr>
+        <td>
+          <ul>
+            <li><var>&lt;Gradle project or sub-project&gt;</var>
+              <ul>
+                <li><var>&lt;Gradle sub-project&gt;</var>
+                  <ul>
+                    <li><span class="use">src</span>/<span 
class="use">main</span>/<span class="del">java</span></li>
+                    <li><span class="use">src</span>/<span 
class="use">test</span>/<span class="del">java</span></li>
+                  </ul>
+                <li>Repeat for other Gradle sub-projects</li>
+              </ul>
+            </li>
+          </ul>
+        </td><td class="next">
+          <ul>
+            <li><var>&lt;Gradle project or sub-project&gt;</var>
+              <ul>
+                <li><span class="use">src</span>/<span 
class="new"><var>&lt;module&gt;</var></span>/<span 
class="use">main</span>/<span class="del">java</span></li>
+                <li><span class="use">src</span>/<span 
class="new"><var>&lt;module&gt;</var></span>/<span 
class="use">test</span>/<span class="del">java</span></li>
+                <li>Repeat for other <abbr title="Java Platform Module 
System">JPMS</abbr> modules</li>
+              </ul>
+            </li>
+            <li>Separated Gradle sub-projects are still possible if 
desired</li>
+          </ul>
+        </td>
+      </tr>
+    </table>
+    <p>
+      When compiling the sources illustrated on the right side above,
+      the root source directory given to the <code>javac</code> command shall 
be the <span class="use">src</span> directory containing all
+      modules rather than the <span class="del">java</span> directory 
containing the <code>org/apache/sis/…</code> hierarchy of packages.
+      The <span class="new"><var>&lt;module&gt;</var></span> directory names 
shall be identical to the module names declared in 
<code>module-info.java</code>.
+      An arbitrary amount of custom directories can be inserted between the 
<span class="new"><var>&lt;module&gt;</var></span> directory
+      and the start of the package directories (e.g. 
<code>org/apache/sis/…</code>).
+      This insertion of custom directories is the difference between <i>Module 
Hierarchy</i>
+      and <i>Module <u>Source</u> Hierarchy</i> in <code>javac</code> 
documentation.
+      The custom directories shall be declared with the 
<code>--module-source-path</code> option like below,
+      where the <code>*</code> character will be automatically replaced by
+      <span class="new"><var>&lt;module&gt;</var></span> by the 
<code>javac</code> compiler:
+    </p>
+    <blockquote><code>
+      javac <b>--module-source-path</b>=<var>/path/to/subproject</var>/<span 
class="use">src</span>/*/<span class="use">main</span>/<span 
class="del">java</span>
+    </code></blockquote>
+    <p>
+      The options for compiling the tests are similar with <span 
class="use">main</span> replaced by <span class="use">test</span>
+      (or anything else at user's choice) like below:
+    </p>
+    <blockquote><code>
+      javac <b>--module-source-path</b>=<var>/path/to/subproject</var>/<span 
class="use">src</span>/*/<span class="use">test</span>/<span 
class="del">java</span>
+    </code></blockquote>
+    <p>
+      Projects are free to add other sub-directories, for example <span 
class="use"><code>resources</code></span>,
+      under the <span class="new"><var>&lt;module&gt;</var></span> directory.
+      Everything that do not match the pattern given to the 
<code>--module-source-path</code> option will be ignored.
+      So the main sources, the tests and the resources can be all located 
under the same module directory,
+      in a way close to Maven convention if desired.
+    </p>
+
+
+
+
+    <h2 id="restructuring">2) Apache SIS restructuring</h2>
+    <p>
+      This section discusses the restructuring of the <a 
href="https://sis.apache.org/";>Apache SIS</a> project
+      following the Module Source Hierarchy. It can been seen as an example of 
one possible approach for dispatching
+      modules between <abbr title="Java Platform Module System">JPMS</abbr> 
modules and Gradle sub-projects.
+      The tree on the left side shows the layout before <abbr title="Spatial 
Information System">SIS</abbr> 1.4,
+      which followed Maven conventions.
+      The tree on the right side shows the new directory layout since 
<abbr>SIS</abbr> 1.4.
+      The <span class="new">names in blue</span> are new directory levels.
+      The <span class="del">names in red</span> are removed directory levels.
+      The <span class="use">names in green</span> are directory levels kept 
unchanged.
+      The <span class="use">src</span>, <span class="use">main</span>,
+      <span class="use">test</span> and <span class="del">java</span>
+      directories are from Maven conventions.
+      Resources are omitted in this discussion for simplicity.
+    </p>
+
+    <table class="two-columns">
+      <tr>
+        <th><abbr>SIS</abbr> 1.3 (Maven layout)</th>
+        <th class="next"><abbr>SIS</abbr> 1.4 (Module Source Hierarchy)</th>
+      </tr>
+      <tr>
+        <td>
+          <pre class="tree"><span class="note">Apache SIS project root</span>
+├── <span class="plain">pom.xml</span>
+├── <span class="del">core</span>
+│   ├── <span class="plain">pom.xml</span>
+│   ├── <span class="del">sis-util</span>
+│   │   ├── <span class="plain">pom.xml</span>
+│   │   └── <span class="use">src</span>
+│   │       ├── <span class="use">main</span>
+│   │       │   └── <span class="del">java</span>
+│   │       │       └── <span class="plain">org/apache/sis/…</span>
+│   │       └── <span class="use">test</span>
+│   │           └── <span class="del">java</span>
+│   │               └── <span class="plain">org/apache/sis/…</span>
+│   ├── <span class="del">sis-metadata</span>
+│   │   └── <span class="note">Same structure, omitted for brevity.</span>
+│   ├── <span class="del">sis-referencing</span>
+│   ├── <span class="del">sis-referencing-by-identifiers</span>
+│   ├── <span class="del">sis-feature</span>
+│   ├── <span class="del">sis-cql</span>
+│   └── <span class="del">sis-portrayal</span>
+├── <span class="del">storage</span>
+│   ├── <span class="plain">pom.xml</span>
+│   ├── <span class="del">sis-storage</span>
+│   │   ├── <span class="plain">pom.xml</span>
+│   │   └── <span class="use">src</span>
+│   │       ├── <span class="use">main</span>
+│   │       │   └── <span class="del">java</span>
+│   │       │       └── <span class="plain">org/apache/sis/…</span>
+│   │       └── <span class="use">test</span>
+│   │           └── <span class="del">java</span>
+│   │               └── <span class="plain">org/apache/sis/…</span>
+│   ├── <span class="del">sis-shapefile</span>
+│   │   └── <span class="note">Same structure, omitted for brevity.</span>
+│   ├── <span class="del">sis-xmlstore</span>
+│   ├── <span class="del">sis-sqlstore</span>
+│   ├── <span class="del">sis-netcdf</span>
+│   ├── <span class="del">sis-geotiff</span>
+│   └── <span class="del">sis-earth-observation</span>
+├── <span class="del">cloud</span>
+│   ├── <span class="plain">pom.xml</span>
+│   └── <span class="del">sis-cloud-aws</span>
+├── <span class="del">profiles</span>
+│   ├── <span class="plain">pom.xml</span>
+│   ├── <span class="del">sis-france-profile</span>
+│   └── <span class="del">sis-japan-profile</span>
+└── <span class="del">application</span>
+    ├── <span class="plain">pom.xml</span>
+    ├── <span class="del">sis-console</span>
+    ├── <span class="del">sis-webapp</span>
+    ├── <span class="del">sis-openoffice</span>
+    └── <span class="del">sis-javafx</span></pre></td>
+
+
+        <td class="next">
+          <pre class="tree"><span class="note">Apache SIS project root</span>
+├── <span class="plain">settings.gradle.kts</span>
+├── <span class="new">endorsed</span>
+│   ├── <span class="plain">build.gradle.kts</span>
+│   └── <span class="use">src</span>
+│       ├── <span class="new">org.apache.sis.util</span>
+│       │   ├── <span class="use">main</span>
+│       │   │   ├── <span class="plain">module-info.java</span>
+│       │   │   └── <span class="plain">org/apache/sis/…</span>
+│       │   └── <span class="use">test</span>
+│       │       └── <span class="plain">org/apache/sis/…</span>
+│       ├── <span class="new">org.apache.sis.metadata</span>
+│       │   └── <span class="note">Same structure, omitted for brevity.</span>
+│       ├── <span class="new">org.apache.sis.referencing</span>
+│       ├── <span class="new">org.apache.sis.referencing.gazetteer</span>
+│       ├── <span class="new">org.apache.sis.feature</span>
+│       ├── <span class="new">org.apache.sis.storage</span>
+│       ├── <span class="new">org.apache.sis.storage.xml</span>
+│       ├── <span class="new">org.apache.sis.storage.sql</span>
+│       ├── <span class="new">org.apache.sis.storage.netcdf</span>
+│       ├── <span class="new">org.apache.sis.storage.geotiff</span>
+│       ├── <span class="new">org.apache.sis.storage.earthobservation</span>
+│       ├── <span class="new">org.apache.sis.cloud.aws</span>
+│       ├── <span class="new">org.apache.sis.portrayal</span>
+│       ├── <span class="new">org.apache.sis.profile.france</span>
+│       ├── <span class="new">org.apache.sis.profile.japan</span>
+│       ├── <span class="new">org.apache.sis.console</span>
+│       ├── <span class="new">org.apache.sis.openoffice</span>
+│       └── <span class="new">org.apache.sis.test</span> <span 
class="note">(new module, see below)</span>
+│           └── <span class="use">test</span>
+│               └── <span class="plain">module-info.java</span>
+├── <span class="new">incubator</span>
+│   ├── <span class="plain">build.gradle.kts</span>
+│   └── <span class="use">src</span>
+│       ├── <span class="new">org.apache.sis.cql</span>
+│       │   ├── <span class="use">main</span>
+│       │   │   ├── <span class="plain">module-info.java</span>
+│       │   │   └── <span class="plain">org/apache/sis/…</span>
+│       │   └── <span class="use">test</span>
+│       │       └── <span class="plain">org/apache/sis/…</span>
+│       ├── <span class="new">org.apache.sis.storage.shapefile</span>
+│       │   └── <span class="note">Same structure, omitted for brevity.</span>
+│       └── <span class="new">org.apache.sis.webapp</span>
+└── <span class="new">optional</span>
+    ├── <span class="plain">build.gradle.kts</span>
+    └── <span class="use">src</span>
+        └── <span class="new">org.apache.sis.gui</span>
+            └── <span class="note">Same structure, omitted for 
brevity.</span></pre>
+        </td>
+      </tr>
+    </table>
+    <p>
+      In the old layout (left side),
+      the Apache <abbr title="Spatial Information System">SIS</abbr> project 
organized modules in some groups:
+      <i>core</i>, <i>storage</i>, <i>cloud</i>, <i>profiles</i> and 
<i>application</i>.
+      While this grouping can be useful for understanding the content
+      of the Apache <abbr title="Spatial Information System">SIS</abbr> 
project,
+      it serves no purpose from the point of view of build management.
+      In the new layout (right side), that grouping is removed from the 
directory tree.
+      Such logical grouping can appear in <abbr title="Java Platform Module 
System">JPMS</abbr>
+      module names if desired, for example 
<code>org.apache.sis.<b>storage</b>.*</code>,
+       <code>org.apache.sis.<b>cloud</b>.*</code> and 
<code>org.apache.sis.<b>profile</b>.*</code>.
+      The old "build-irrelevant" grouping is replaced by a new grouping which 
is relevant to the build:
+    </p>
+    <ul>
+      <li>The <b>endorsed</b> sub-project contains all modules that are 
included in
+          official Apache <abbr title="Spatial Information System">SIS</abbr> 
releases.</li>
+      <li>The <b>incubator</b> sub-project contains modules that are not yet 
ready for release.</li>
+      <li>The <b>optional</b> sub-project contains modules requiring agreement 
with license terms
+          more restrictive than Apache 2.</li>
+    </ul>
+    <p>
+      With the new layout, modules that are not ready for release can be 
easily excluded all together.
+      By comparison, with the old layout the release manager had to manually 
exclude various modules
+      scattered in the tree.
+      Likewise, the optional modules can be included or excluded all together 
depending on license agreement.
+      For example the <abbr title="Graphical User Interface">GUI</abbr> 
depends on JavaFX and can be included
+      in the build only on acceptance of <abbr title="GNU General Public 
License">GPL</abbr> terms.
+      This new way of grouping modules will hopefully simplify
+      Apache <abbr title="Spatial Information System">SIS</abbr> releases.
+    </p>
+    <h3>2.1) Consequence on cross-module dependencies</h3>
+    <p>
+      In the new layout, the replacement of Maven modules by <abbr title="Java 
Platform Module System">JPMS</abbr>
+      modules has a desirable side-effect.
+      In the old layout, any Maven module could depend on any other Maven 
module as long as there is no cycle.
+      Maven determines the modules build order regardless if modules belong to 
the same groups or not.
+      So nothing (except cycles) prevented a module in the <span 
class="del">core</span> group to depend
+      on a module in incubation or subject to restrictive license terms.
+      With the new layout, the <span class="new">endorsed</span>, <span 
class="new">incubator</span> and
+      <span class="new">optional</span> sub-projects are the finest level of 
grouping managed by the build system.
+      The <abbr title="Java Platform Module System">JPMS</abbr> modules inside 
those sub-projects cannot be managed
+      independently by the build system, which has advantages and inconvenient.
+      An advantage for Apache <abbr title="Spatial Information 
System">SIS</abbr> is that compile-time dependency of
+      <span class="new">endorsed</span> modules toward any <span 
class="new">incubator</span> or
+      <span class="new">optional</span> modules become impossible
+      (however, runtime dependency through Service Provider Interfaces is 
still possible).
+    </p>
+    <h3>2.2) Dropping the separation between source and resources</h3>
+    <p>
+      For the Apache <abbr title="Spatial Information System">SIS</abbr> 
restructuring,
+      the <span class="del">java</span> directory has been dropped.
+      The consequence is that resources are no longer separated from Java 
source code.
+      The Maven's convention putting resources in a separated directory 
hierarchy
+      is considered a good practice by some, but this is not an universal 
opinion.
+      NetBeans Ant projects and OpenJDK for example don't do that.
+      The argument is similar to documentation, which was traditionally 
separated from the code in previous programming languages.
+      The Java designers decided that the best place to put documentation 
(javadoc) was close to the code.
+      Having resources close to the code has similar advantages.
+      It makes more likely that the developer sees when a change in a class 
may require a change in a resource,
+      and less tedious to open that file (no need to navigate through the 
exact same path in a separated directory hierarchy).
+      Furthermore, the Maven's convention separating <span 
class="del">java</span> and <span class="del">resources</span>
+      does not work well in a multi-languages project anyway, because it does 
not distinguish
+      the Java resources to copy in a <abbr title="Java Archive 
File">JAR</abbr> file
+      from the C/C++ or Python resources (for example).
+      Mixing two languages in the same module happens when the module is a 
bridge between those two languages,
+      such as <a href="https://github.com/OSGeo/PROJ-JNI";>PROJ-JNI</a> 
(between Java and C/C++)
+      and <a href="http://www.geoapi.org/java-python/index.html";>GeoAPI 
bridge</a> (between Java and Python).
+    </p>
+    <h3>2.3) Test module</h3>
+    <p>
+      The new layout contains a module, named <span 
class="new"><code>org.apache.sis.test</code></span>,
+      that did not existed in the old layout. This module is local to the 
build and never deployed.
+      It has no <code><span class="use">main</span></code> sub-directory,
+      only a <code><span class="use">test</span>/module-info.java</code> file.
+      This is a convenient way to declare dependencies that are needed by the 
tests
+      but not declared in any <code><span 
class="use">main</span>/module-info.java</code> file being compiled.
+      Actually our experiments suggest that the <code>--add-reads</code> 
option does not work well if the added
+      module does not appear in a <code>requires</code> clause of at least one 
<code>module-info.java</code> file.
+      The <span class="new"><code>org.apache.sis.test</code></span> module 
resolves that problem.
+    </p><p>
+      Maven has a different approach which allows the tests to overwrite the 
main <code>module-info</code> files.
+      We don't do that because those files are sometime a bit large,
+      and we want to avoid the risk of overwriting them with
+      <code><span class="use">test</span>/module-info.java</code> files that 
differ in unintended ways.
+      Instead the <span class="new"><code>org.apache.sis.test</code></span> 
module information
+      is added to the <code>module-info</code> files of all modules to test 
without overwriting them.
+    </p>
+
+
+
+
+    <h2 id="gradle-config">3) Gradle configuration for Module Source 
Hierarchy</h2>
+    <p>
+      It is possible to get Gradle to work to some extent without writing a 
custom plugin.
+      The hacks are not very clean, but could be much better with a little bit 
of improvement from Gradle.
+      The "<a href="#gradle-proposals">Ideas for Gradle evolution</a>" section 
provides some proposals.
+      The key information that needs to be supplied are:
+    </p>
+    <ul>
+      <li>For compiling the main code:
+        <ul>
+          <li><code><b>--module-path</b></code> <var>&lt;paths to all 
dependencies&gt;</var></li>
+          <li><code><b>--module-source-path</b> 
/<var>path_to_sub_project</var>/<span class="use">src</span>/*/<span 
class="use">main</span>/<span class="del">java</span></code></li>
+          <li><code><b>--add-modules</b> 
<var>module_1</var>,<var>module_2</var>,<var>module_3</var>,</code>…
+              (list all modules of the project to compile, not 
dependencies)</li>
+        </ul>
+      </li>
+      <li>For compiling the test code:
+        <ul>
+          <li><code><b>--module-path</b></code> <var>&lt;paths to dependencies 
including the directory containing the output of above compilation of main 
modules&gt;</var></li>
+          <li><code><b>--module-source-path</b> 
/<var>path_to_sub_project</var>/<span class="use">src</span>/*/<span 
class="use">test</span>/<span class="del">java</span></code></li>
+          <li><code><b>--patch-module</b> 
<var>module_1</var>=<var>/path_to_sub_project</var>/<span 
class="use">src</span>/<var>module_1</var>/<span class="use">test</span>/<span 
class="del">java</span></code>
+              (repeat for each module)</li>
+          <li><code><b>--add-modules</b></code> <var>&lt;same as for 
compilation of main code&gt;</var></li>
+          <li><code><b>--add-reads</b> 
<var>module_1</var>=<var>dependency_A</var>,<var>dependency_B</var>,</code>… 
for all test-only dependencies such as JUnit
+              (repeat for each module)</li>
+        </ul>
+      </li>
+      <li>For executing the test code:
+        <ul>
+          <li><code><b>--module-path</b></code> <var>&lt;paths to dependencies 
and compilation result of main modules, but <strong>excluding compilation 
result of test classes</strong>&gt;</var></li>
+          <li><code><b>--patch-module</b> 
<var>module_1</var>=<var>${buildDir}</var>/classes/java/test/<var>module_1</var></code>
+              (repeat for each module)</li>
+          <li><code><b>--add-modules</b></code> <var>&lt;same as for 
compilation of main code&gt;</var></li>
+          <li><code><b>--add-reads</b></code> (as needed for test-only 
dependencies)</li>
+          <li><code><b>--add-opens</b></code> (as needed for Jakarta or other 
libraries based on reflection)</li>
+          <li><code><b>--add-exports</b></code> (as needed for allowing JUnit 
to test private package)</li>
+        </ul>
+      </li>
+    </ul>
+    <p>
+      <code>build.gradle.kts</code> fragments are shown in the
+      <a href="https://geomatys.github.io/draft/Modularization.html";>draft 
version of this page</a>.
+      This complexity can be handled by a customized Gradle plugin in Java. 
Details about how to do so are given in the
+      <a 
href="https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html";>Gradle
 documentation</a>
+      and are not repeated here. Some parts that can be moved from 
<code>build.gradle.kts</code> script to Java code
+      are the full <code>sourceSets</code> configuration, together with the 
class-path and module-path settings,
+      and the <code>--source-module-path</code>, <code>--add-modules</code> 
and <code>--patch-modules</code> options.
+      Some (but not all) <code>--add-exports</code> options can also be 
managed by the plugin.
+      Source code of a plugin developed specifically for Apache SIS is in the 
following sub-directory:
+    </p>
+    
<blockquote><code>buildSrc/src/org.apache.sis.buildtools/main/org/apache/sis/buildtools/gradle/</code><br>
+    in particular the <code>ModularCompilation</code> and 
<code>ModularTest</code> classes.</blockquote>
+
+    <h3 id="gradle-issues">3.1) Gradle issues and workarounds</h3>
+    <p>
+      Above configuration works but has the following problems with Gradle 8.2.
+      Workarounds for current Gradle version are presented in this section.
+      Proposed Gradle evolutions are presented in a <a 
href="#gradle-proposals">later section</a>.
+      The issue that caused the greatest difficulties is the Gradle automatic 
dispatching
+      of dependencies between the <code>--class-path</code> and 
<code>--module-path</code> options,
+      which is discussed first.
+      That black magic was very close to be a <a href="#maven-bug">blocker 
issue because it does the wrong thing</a>.
+      The other issues are less critical and could be summarized as
+      "Insufficient control on the options passed to the command".
+      The ease of use issue is discussed in a <a 
href="#gradle-proposals">separated section</a>.
+    </p>
+    <h4>3.1.1) Automatic dispatching between class-path and module-path does 
not work</h4>
+    <p>
+      Gradle uses a set of heuristic rules for deciding if a dependency should 
be declared on the class-path or on the module-path.
+      But heuristic rules tend to work well only in some specific contexts, 
which is currently restricted to package hierarchy.
+      As of Gradle 8.2.1, those heuristic rules do not recognize any module in 
our Source Module Hierarchy.
+      In particular, the automatic dispatching of dependencies is enabled only 
if Gradle believes that the
+      sub-project being compiled is itself a <abbr title="Java Platform Module 
System">JPMS</abbr> module,
+      and Gradle does not recognize Module Hierarchy as such. The Gradle's
+      <a 
href="https://docs.gradle.org/8.2/javadoc/org/gradle/api/jvm/ModularitySpec.html";><code>ModularitySpec</code></a>
+      class does not provide an option for forcing the activation of automatic 
dispatching.
+      The current workaround is to make explicit calls to methods of Gradle 
API such as
+      <code>setClasspath(…)</code> for overwriting the class-path and 
module-path defined by Gradle.
+    </p><p style="color:crimson">
+      <b>Note:</b> above paragraph explains the issue when building the 
library project.
+      In that case the burden of applying workaround falls on us, which we 
accept to do.
+      However the same issue (wrong dispatching) hits also all external 
projects using the library,
+      <em>potentially breaking any <abbr title="Java Platform Module 
System">JPMS</abbr> library
+      (not only Apache SIS) for all users of that library in a 
non-<abbr>JPMS</abbr> project.</em>
+      This is not a <abbr>JPMS</abbr> problem, this is a Maven 3.8.6 (or maybe 
Plexus) mishandling
+      which is also replicated in Gradle 8.2.1.
+      See <a href="#maven-bug">Quasi-blocker Maven bug</a> for details.
+    </p>
+    <h4>3.1.2) Automatic dispatching between class-path and module-path is not 
always desirable</h4>
+    <p>
+      The Gradle <code>ModularitySpec</code> implementation could be improved 
for recognizing a larger set of hierarchies,
+      but even better automatic detection will not always work.
+      Sometime we want to force a dependency to be on the module-path no 
matter what Gradle thinks.
+      It happens for example when a dependency has no 
<code>module-info.class</code> file
+      and no <code>Automatic-Module-Name</code> entry in the 
<code>MANIFEST.MF</code> file,
+      but we still want to handle it as an automatic module.
+      Some may argue that this is bad practice, but this is sometime necessary 
for getting tools to work.
+      In Apache <abbr>SIS</abbr> case, all those automatic modules are 
optional dependencies.
+      We need a way to control whether a dependency should be considered as a 
module or not on a case-by-case basis.
+    </p>
+    <h4>3.1.3) Unexpected class-path changes after configuration</h4>
+    <p>
+      In the Javadoc task, it is difficult to modify the class-path and 
module-path options
+      because the class-path is modified again by Gradle after our 
configuration.
+      So the class-path was incomplete at the time we copied its entries to 
the module-path,
+      and the class-path receives undesired new entries after we cleared it.
+      This behavior causes Javadoc generation to fail, with no workaround we 
could find so far.
+      However a manual workaround exists by opening the 
<code>build/tmp/javadoc/javadoc.options</code>
+      file in an editor, move the <code>-classpath</code> content to 
<code>--module-path</code>,
+      then run <code>javadoc @build/tmp/javadoc/javadoc.options</code> on the 
command line.
+      Because Javadoc are generated less often than compilation,
+      we think that this workaround is acceptable until a better solution 
become available.
+    </p>
+    <h4>3.1.4) Repeated module path</h4>
+    <p>
+      Adding the <code>--module-path</code> in the compiler options cause the 
option to appear twice
+      in the debug output of Gradle 8.2. The two occurrences have the exact 
same path, which may be large.
+      We found no way to prevent that duplication, as it does not appear in 
the list returned by
+      <a 
href="https://docs.gradle.org/8.2/javadoc/org/gradle/api/tasks/compile/CompileOptions.html#getCompilerArgs--";><code>CompilerOptions.getCompilerArgs()</code></a>.
+      Our current workaround is to do nothing,
+      as <code>javac</code> seems to work anyway with duplicated elements on 
the module path.
+    </p>
+    <h4>3.1.5) Source path incompatibility</h4>
+    <p>
+      In the same way that <code>--class-path</code> and 
<code>--module-path</code> should specify mutually exclusive sets,
+      <code>--source-path</code> and <code>--module-source-path</code> should 
also be mutually exclusive options.
+      The <code>--source-path</code> option is considered rarely needed in 
modern builds and can be omitted.
+      But the Gradle's debug output seems to unconditionally provide the 
latter option at least with an empty string,
+      because the empty string has a different meaning than the default 
<code>javac</code> value.
+      Using the Gradle <abbr>API</abbr> for setting the source path to 
<code>null</code> does not help since Gradle
+      <a 
href="https://docs.gradle.org/8.2/javadoc/org/gradle/api/tasks/compile/CompileOptions.html#getSourcepath--";>interprets
 that as an empty path</a>.
+      We saw no <abbr>API</abbr> for telling Gradle to omit completely that 
option.
+      This is a problem since the <code>--module-source-path</code> option is 
necessary for specifying the
+      <code><span class="use">src</span>/<span class="new">*</span>/<span 
class="use">main</span>/<span class="del">java</span></code> pattern.
+      Consequently when launching <code>javac</code> on the command-line with 
the options shown by Gradle's debug output,
+      we get the following error:
+    </p>
+    <blockquote><code>error: cannot specify both --source-path and 
--module-source-path</code></blockquote>
+    <p>
+      Our current workaround is to do nothing.
+      The Java compiler seems to work inside Gradle, even if it doesn't work 
on the command-line with Gradle's debug output.
+    </p>
+
+
+
+
+    <h2 id="advantages">4) Advantages of Source Module Hierarchy</h2>
+    <p>
+      The use of <i>Module Source Hierarchy</i> instead of <i>Package 
Hierarchy</i> has advantages and inconvenient.
+      Advantages for the Apache <abbr title="Spatial Information 
System">SIS</abbr> project are described below.
+      The main inconvenient is the poor support in current build tools and
+      <abbr title="Integrated Development Environment">IDE</abbr>.
+      However the latter is not a blocker, and we can try to contribute in 
improving the situation with proposals
+      such as the "<a href="#gradle-proposals">Ideas for Gradle evolution</a>" 
section at the bottom of this page.
+    </p>
+    <h3>4.1) Aggregated output generation without resorting to hacks</h3>
+    <p>
+      Most JDK tools are <abbr title="Java Platform Module System">JPMS</abbr> 
aware
+      and can process many modules in one invocation of each command-line tool.
+      In some cases, the same result can be obtained by invoking the same tool 
repetitively for each module, but not always.
+      The most obvious example where the result differs is 
<code>javadoc</code>.
+      When executed for a group of modules instead of invoked repetitively for 
each module,
+      <code>javadoc</code> can generate an aggregated <abbr title="Application 
Programming Interface">API</abbr> documentation
+      with a home page listing all modules, an index with entries from all 
modules,
+      hyper-links to modules beyond the boundary of what is declared in 
<code>module-info</code>
+      (for example lists of all implementations of each interface), <i>etc.</i>
+      Such aggregation does not fit naturally in the Maven directory layout.
+      Maven does support aggregated Javadoc, but this support requires hacks 
and may not be easily applicable to other tools.
+      An example of another tool for which aggregated execution is sometime 
useful is annotation processor.
+      More use cases may appear in future Java versions.
+      A native support of Module Source Hierarchy in Gradle would make easier 
to leverage those features
+      with less needs to resort to hacks.
+    </p>
+    <h3>4.2) Compile-time verification of forward references</h3>
+    <p>
+      Suppose that module <var>B</var> depends on module <var>A</var>.
+      Module <var>B</var> can have compile-time dependencies toward 
<var>A</var> (backward references),
+      but the converse (a forward reference from <var>A</var> to <var>B</var>)
+      is illegal for the compiler except in <code>module-info</code>.
+      However such forward references are perfectly legal in 
<em>documentation</em>,
+      and indeed the <code>javadoc</code> tool handles them well.
+      It is possible to write Javadoc <code>{@link}</code> and 
<code>{@see}</code> tags in module <var>A</var> with
+      forward references to some <abbr title="Application Programming 
Interface">API</abbr> in module <var>B</var>.
+      However doing so with Maven directory layout requires that we sacrifice 
a safety.
+      The <code>javac</code> tool offers the possibility to verify Javadoc 
<code>{@link}</code> and <code>{@see}</code>
+      tags at compile-time. This feature offers much faster error detections 
than waiting for Javadoc generation,
+      because the latter is done less frequently than compilation.
+      This verification can be enabled by passing the 
<code>-Xdoclint:all</code> option to <code>javac</code>,
+      in which case any invalid <code>{@link}</code> or <code>{@see}</code> 
tag causes a compilation error.
+      It works well with references to <abbr title="Application Programming 
Interface">API</abbr> in the same module
+      or in dependencies, but cannot work with forward references unless 
<code>javac</code> knows that those modules
+      exist and what they contain.
+      This is possible with Module Source Hierarchy, but not with Maven 
directory layout.
+      With the latter, all forward references are flagged as errors.
+      With the former, compile-time verification of <code>{@link}</code> or 
<code>{@see}</code> tags,
+      including forward references, works like a charm.
+    </p><p>
+      Another place where forward references are used is in 
<code>module-info</code> files.
+      The <code>opens</code> and <code>exports</code> statements can be 
qualified,
+      i.e., a package can be exported only to some specific modules.
+      Those modules are forward references, because they are dependents rather 
than dependencies.
+      But without Module Source Hierarchy, it is difficult for the compiler to 
know what those dependents are,
+      so any use of qualified exports generally produces warnings like below:
+    </p>
+    <blockquote>
+      
<code>endorsed/src/org.apache.sis.metadata/main/module-info.java:164:</code>
+      warning: [module] module not found: <code>org.apache.sis.gui</code>
+    </blockquote>
+
+    <h3>4.3) Easier reuse of test fixtures</h3>
+    <p>
+      The test code for a module may create test fixtures, mocks or assertion 
methods
+      that we want to reuse in the test code of dependent modules.
+      With Maven, we have to package the test classes in an artifact of type 
<code>test-jar</code>.
+      With the module source hierarchy, this is no longer necessary if the 
test fixtures are reused
+      only inside the same sub-project. For example if test fixtures are 
provided in the
+      <code>org.apache.sis.test</code> package under the
+      <code><span class="use">test</span>/<span class="del">java</span></code>
+      sub-directory of the <code>org.apache.sis.util</code> module,
+      then all other modules in the same sub-project can access those text 
fixture by adding
+      the following script in the <code>build.gradle.kts</code> file,
+      with nothing to package or deploy:
+    </p>
+    <pre class="snippet">tasks.compileTestJava {
+    <span class="note">(…snip…)</span>
+
+    var <var>allModules</var> = file("<span 
class="use">src</span>").list().joinToString(separator=<span 
class="string">","</span>)
+    args.add(<span class="string">"--add-exports"</span>)
+    args.add(<span 
class="string">"org.apache.sis.util/org.apache.sis.test=${<var>allModules</var>}"</span>)
+}</pre>
+
+    <h3>4.4) Control on test environment</h3>
+    <p>
+      A side-effect of the restructuring described in this page is that the 
tests of all modules in a Gradle sub-project
+      are executed together in the same <abbr title="Java Virtual 
Machine">JVM</abbr>.
+      It may be considered against unit test principles, but actually this is 
controllable.
+      First we note that having all modules in the <abbr title="Java Virtual 
Machine">JVM</abbr>
+      during test execution is not necessarily a bad thing.
+      It sometime happens that a test behaves differently when the module is 
alone in the <abbr>JVM</abbr>
+      compared to when all modules are present.
+      Because the latter scenario is more representative of production 
environment than the former,
+      some bugs can be unnoticed because of module isolation during tests.
+      Some peoples will argue that integration tests should have discovered 
such bugs,
+      but it is hard to have an extensive coverage for all kinds of tests.
+      With the Module Source Hierarchy, the easiest configuration is to let 
all tests
+      be executed in the same <abbr title="Java Virtual Machine">JVM</abbr>.
+      However it is possible to filter which modules to load in the 
<abbr>JVM</abbr>
+      with options such as <code>--limit-modules</code>.
+      It should be possible to improve Gradle with options for making easy to 
run different
+      subsets of the tests with different subsets of modules loaded.
+    </p>
+    <h3>4.5) Speed</h3>
+    <p>
+      We have not done serious benchmarks, but compiling all modules from 
scratch seems a little bit faster when
+      <code>javac</code> is invoked once for all modules compared to invoking 
<code>javac</code> for each module.
+      Likewise, tests are also faster presumably because common dependencies 
are loaded only once and the caching
+      mechanisms of the tested application takes effect
+      (see the previous section for a discussion about running the tests of 
all modules together).
+      In Apache <abbr title="Spatial Information System">SIS</abbr> case, the 
build time is reduced by about 30%.
+      However, speed was not the main goal for this restructuring.
+    </p>
+
+
+
+
+    <h2 id="limitations">5) Limitations of Source Module Hierarchy</h2>
+    <p>
+      The Module Source Hierarchy is not best suited to every situations.
+      This section describes some cases where the Maven hierarchy currently 
supported by Gradle may be better suited.
+    </p>
+    <h3>5.1) No support from main build tools</h3>
+    <p>
+      As of October 2023, neither Maven or Gradle provides out-of-the-box 
support for Module Source Hierarchy.
+      A very good out-of-the-box support (actually the major source of 
inspiration for the proposal in this page)
+      is provided by the NetBeans <abbr>IDE</abbr> when using the NetBeans Ant 
build system,
+      but the NetBeans community itself encourages the use of Maven or Gradle 
instead of Ant.
+      Nevertheless, the flexibility of Gradle compared to Maven makes possible 
to use Module Source Hierarchy
+      with some efforts, but the task could be made much easier with a little 
bit of Gradle improvements
+      such as the ones proposed <a href="#gradle-proposals">at the end of this 
page</a>.
+    </p>
+    <h3>5.2) Generated code seems difficult to add</h3>
+    <p>
+      As of Gradle 8.2, the ANTLR task
+      <a 
href="https://discuss.gradle.org/t/antlr-plugin-directory-issues-gradle-2-7/17889";>does
 not work well
+      with arbitrary source directories</a>. We have to keep the default 
conventions of the ANTLR plugin even
+      if those conventions do not fit well in Module Source Hierarchy.
+      Another problem is that we didn't found the right compiler options for 
combining a directory
+      of generated sources with the main sources in a Module Source Hierarchy, 
so we have to write
+      the output directly in main source directory. In Apache <abbr>SIS</abbr> 
case this problem
+      is hopefully temporary, because we plan to replace ANTLR generated code 
by hand-written code.
+    </p>
+    <h3 id="NetBeans">5.3) Not rendered well in NetBeans 18</h3>
+    <p>
+      IntelliJ seems to open the Apache SIS Gradle project with Module Source 
Hierarchy, but NetBeans has some glitches.
+      As a workaround, Apache <abbr>SIS</abbr> provides a 
<code>netbeans-project</code> directory that NetBeans user can open.
+    </p>
+
+
+
+
+    <h2 id="maven-bug">6) Quasi-blocker Maven bug</h2>
+    <p>
+      When invoking Java tools such as <code>java</code>, <code>javac</code> 
or <code>javadoc</code>,
+      the project dependencies can be put either on the class-path or on the 
module-path using the
+      command-line <code>--class-path</code> and <code>--module-path</code> 
options respectively.
+      Maven 3.8.6 and Gradle 8.2.1 use automatically the module-path if all 
the following conditions are true:
+    </p>
+    <ol>
+      <li>the dependency is modularized (i.e. contains a 
<code>module-info.class</code> file
+        or an <code>Automatic-Module-Name</code> attribute in 
<code>MANIFEST.MF</code>), and</li>
+      <li>the project using the dependency is itself modularized.</li>
+    </ol>
+    <p>
+      Condition #1 is okay as a default, but #2 is problematic.
+      The fact that a dependency is declared on the class-path rather than the 
module-path
+      changes the way that <code>java.<wbr/>util.<wbr/>ServiceLoader</code> 
discovers the provided services.
+    </p>
+    <ul>
+      <li>If the dependency is on the class-path, <code>ServiceLoader</code> 
scans the content
+        of <code>META-INF/services</code> directory.</li>
+      <li>If the dependency is on the module-path, <code>ServiceLoader</code> 
uses the declarations
+        in <code>module-info.class</code>.</li>
+    </ul>
+    <p>
+      Even if condition #2 is false (i.e. a project is not modularized), 
modularized dependencies still
+      need to be declared on the module-path <em>for allowing the dependency 
to discover its own services,
+      or the services of a transitive modularized dependency</em>.
+      If a modularized dependency is put on the class-path instead,
+      it has consequence not only for the project using that dependency,
+      <strong>but also for the dependency itself, which become unable to use 
its own module-info.class.</strong>
+      This is demonstrated by a <a 
href="https://github.com/Geomatys/MavenModulepathBug";>small test case on 
GitHub</a>,
+      together with two <code>java</code> command-lines reproducing the Maven 
behavior followed by the desired behavior.
+    </p><p>
+      Unless Maven provides some configuration options that we did not see, 
the way that Maven decides what to
+      put on <code>--class-path</code> and what to put on 
<code>--module-path</code> is a quasi-blocker issue
+      for gradual modularisation of large projects. It is so because the 
consequences of dispatching <abbr>JAR</abbr>
+      files on class-path versus module-path is not limited to the project 
<em>using</em> those <abbr>JAR</abbr> files.
+      The consequences apply also to the <em>libraries</em> inside those 
<abbr>JAR</abbr> files themselves,
+      even if those libraries were fully built as <abbr title="Java Platform 
Module System">JPMS</abbr> modules.
+      There is various <abbr>JDK</Abbr> methods that behave differently 
depending on whether the code invoking
+      those methods were inside a <abbr>JAR</abbr> file specified on the 
class-path or a <abbr>JAR</abbr> file
+      specified on the module-path. Those methods are identified by the 
<code>@CallerSensitive</code> annotation
+      in the <abbr>JDK</abbr> source code and include not only above-cited 
<code>java.<wbr/>util.<wbr/>ServiceLoader</code>,
+      but also <code>ClassLoader.<wbr/>getResource<wbr/>(String)</code> and 
more.
+    </p>
+    <h3>6.1) Workaround</h3>
+    <p>
+      The workaround for library developers is to declare all service 
providers in both
+      <code>module-info</code> file and <code>META-INF/services/</code> 
directory, with the risk of inconsistencies.
+      This workaround may force developers to renounce to the usage of 
<code>provider()</code> static methods,
+      because that method works only for providers declared in 
<code>module-info</code>.
+      It means that developers must renounce to provide singleton instances of 
their service providers
+      (that problem can sometime be mitigated with wrappers).
+    </p><p>
+      Note that this workaround does not fix the real issue,
+      which is that dependencies are loaded as unnamed modules when they 
should not.
+      The workaround allows libraries and applications to find some service 
providers despite this problem,
+      but any other features that depend on named modules are still broken.
+      Even the service providers may not work as intended despite the 
<code>META-INF/services</code> duplication,
+      because of the impossibility to reproduce exactly the 
<code>provider()</code> method behavior.
+    </p><p>
+      Issue on Maven JIRA tracker: <a 
href="https://issues.apache.org/jira/browse/MNG-7855";>MNG-7855</a>
+    </p>
+
+
+
+
+    <h2 id="conclusion">7) Conclusion</h2>
+    <p>
+      Maven and Gradle uses "convention-over-configuration" approach to build 
<abbr>JVM</abbr>-based project.
+      A problem with that approach is that it works well for a few years,
+      but when the convention become no longer suited to the language 
evolution,
+      it is very difficult to changes the habits.
+      Maven rigid conventions may be a reason for the slow <abbr title="Java 
Platform Module System">JPMS</abbr> adoption.
+    </p>
+    <h3 id="gradle-proposals">7.1) Ideas for Gradle evolution</h3>
+    <p>
+      Full <abbr title="Java Platform Module System">JPMS</abbr> support,
+      i.e. having the possibility to use the <code>javac</code> <i>Module 
Source Hierarchy</i> when desired
+      instead of being restricted to the <i>Package Hierarchy</i>, has some 
advantages described in this page.
+      But there is also inconvenient, largely caused by build tools 
limitations.
+      Gradle could help in different ways, described below.
+      The most critical issue, almost a blocker, is the first one.
+    </p>
+    <h4>7.1.1) Explicit control over "class-path versus module-path" 
detection</h4>
+    <p>
+      The current automatic dispatching of dependencies on class-path 
<i>versus</i> module-path does not work with Module Source Hierarchy.
+      Even if it was fixed, it would break again if a new hierarchy was 
introduced in the future.
+      Even if an automagic algorithm was able to work for every hierarchies, 
automatic dispatching is not always desirable.
+      Sometime the developer really wants a dependency to be declared on 
<code>--module-path</code> even if it is not modularized,
+      because the consequences on the modules that use this dependency are not 
the same.
+    </p><p>
+      We could complete or replace the <code>inferModulePath</code> property in
+      <a 
href="https://docs.gradle.org/8.2/javadoc/org/gradle/api/jvm/ModularitySpec.html";><code>ModularitySpec</code></a>
+      for making possible to force the automatic dispatching of dependencies 
between class-path and module-path
+      without relying on the conditions documented in the 
<code>getInferModulePath()</code> method.
+      Alternatively Gradle could be enhanced for recognizing the Source Module 
Hierarchy itself.
+      But in any cases, we would still need a way to <em>force</em> a 
dependency to be on the module-path no matter what Gradle thinks.
+    </p>
+    <h4 id="javac-options">7.1.2) Full control over all Java compiler 
options</h4>
+    <p>
+      Provide a way to set the all compiler options, including the ones 
managed by Gradle itself.
+      Currently the <a 
href="https://docs.gradle.org/8.2/javadoc/org/gradle/api/tasks/compile/CompileOptions.html";><code>CompilerOptions</code></a>
+      class has a <code>getCompilerArgs()</code> method providing a mutable 
list,
+      but that list is only for <em>additional</em> options appended after the 
options managed by Gradle.
+      There is also a <code>get<u>All</u>CompilerArgs()</code> method, but 
that list is unmodifiable.
+      The reason why full control on all compiler options is sometime desired
+      is because latest Java releases may have new features that are 
incompatible with the options managed by Gradle.
+      An example of incompatible Java compiler options is 
<code>--module-source-path</code> versus <code>--source-path</code>.
+      Even if Gradle resolves this incompatibility, other incompatible options 
existed in the past
+      (for example <code>-release</code> versus <code>-source</code> and 
<code>-target</code>) and
+      we cannot know in advance what will be the next incompatible options in 
future Java releases.
+      We may also want to do cleanups such as removing the 
<code>--module-path</code> duplication.
+    </p><p>
+      The same argument applies to other tools as well.
+      Currently the lack of full control on <code>javadoc</code> options is a 
blocker issue for generating the Javadoc,
+      forcing us to launch <code>javadoc</code> directly on the command-line 
instead.
+      We accept this problem as a hopefully temporary inconvenience since 
Javadoc is not generated
+      as often as the <abbr>JAR</abbr> files.
+    </p>
+    <h4>7.1.3) Allow to specify the test classes as a list of 
<code>java.lang.Class</code> objects</h4>
+    <p>
+      The test classes are currently specified as a list of files.
+      Gradle infers the class name from the file name, then invoke 
<code>Class.forName(String, ClassLoader)</code>.
+      But the class name inferred by Gradle is wrong when the project layout 
is not as expected by Gradle.
+      Other reasons why developers way want to instantiate the 
<code>Class</code> themselves may be if they need
+      some control on the <code>ClassLoader</code> or <code>ModuleLayer</code> 
to use for loading the classes.
+    </p>
+    <h4>7.1.4) Easier way to add <code>--add-exports</code> options</h4>
+    <p>
+      It is currently tedious to add <code>--add-reads</code> and 
<code>--add-exports</code> options.
+      Furthermore the same options need to be specified in different places, 
such as <code>javac</code>
+      and the <code>java</code> command for executing tests. A convenient 
place where some options could
+      be specified would be in the dependency declarations, because the 
options usually need to be the same
+      for all usage of a dependency. An example is given in the
+      <a href="https://geomatys.github.io/draft/Modularization.html";>draft 
version of this page</a>.
+    </p>
+    <h3 id="links">7.2) Links to issues and test cases</h3>
+    <p>Test cases demonstrating the problem, and issues created on bug 
trackers:</p>
+    <ul>
+      <li><a href="https://issues.apache.org/jira/browse/MNG-7855";>MNG-7855 on 
Maven JIRA</a></li>
+      <li><a href="https://github.com/gradle/gradle/issues/25954";>Issue #25954 
on Gradle GitHub</a> — Dependencies wrongly put on class-path rather than 
module-path</li>
+      <li><a href="https://github.com/gradle/gradle/issues/25962";>Issue #25962 
on Gradle GitHub</a> — Full control over all options given to Java tools</li>
+      <li><a href="https://github.com/gradle/gradle/issues/25974";>Issue #25974 
on Gradle GitHub</a> — Support Module Source Hierarchy</li>
+      <li><a href="https://github.com/Geomatys/MavenModulepathBug";>Maven and 
Gradler test case</a></li>
+    </ul>
+  </body>
+</html>

Reply via email to