Merge branch 'geoapi-3.1': port fixes from Apache SIS 1.0-RC1.
diff --git a/application/sis-console/pom.xml b/application/sis-console/pom.xml
index ba3cdb3..0296b0d 100644
--- a/application/sis-console/pom.xml
+++ b/application/sis-console/pom.xml
@@ -145,6 +145,10 @@
       <version>${project.version}</version>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>jakarta.xml.bind</groupId>
+      <artifactId>jakarta.xml.bind-api</artifactId>
+    </dependency>
 
     <!-- Test dependencies -->
     <dependency>
diff --git a/application/sis-console/src/main/artifact/README b/application/sis-console/src/main/artifact/README
index ce5f727..d7f1562 100644
--- a/application/sis-console/src/main/artifact/README
+++ b/application/sis-console/src/main/artifact/README
@@ -13,7 +13,9 @@
 Installation
 ============
 
-SIS is based on Java 8 and provided as a unique standalone JAR file.
+SIS requires Java 8 or later. If running on Java 9 or later,
+then the Derby JAR file should be added in the bin/ directory.
+See http://sis.apache.org/epsg.html#command-line
 
 Unix
 ----
diff --git a/application/sis-console/src/main/artifact/lib/README b/application/sis-console/src/main/artifact/lib/README
index ab4d188..aeb28ea 100644
--- a/application/sis-console/src/main/artifact/lib/README
+++ b/application/sis-console/src/main/artifact/lib/README
@@ -2,6 +2,7 @@
 Recognized optional dependencies are:
 
   - Derby database
+  - JAXB implementation
   - UCAR netCDF library
   - ESRI Geometry API
   - Java Topology Suite
diff --git a/core/sis-build-helper/src/main/ant/prepare-release.xml b/core/sis-build-helper/src/main/ant/prepare-release.xml
index a821354..6fffb54 100644
--- a/core/sis-build-helper/src/main/ant/prepare-release.xml
+++ b/core/sis-build-helper/src/main/ant/prepare-release.xml
@@ -34,34 +34,10 @@
                   match = "MINOR_VERSION\s*\+\s*&quot;-SNAPSHOT&quot;"
                 replace = "MINOR_VERSION"/>
 
-    <!-- Replace URL to trunk by URL to the branch on Subversion. -->
-    <replace dir="${user.dir}" failOnNoReplacements="true">
-      <include name="**/pom.xml"/>
-      <replacefilter token="svn.apache.org/repos/asf/sis/trunk"
-                     value="svn.apache.org/repos/asf/sis/branches/${branch.version}"/>
-      <replacefilter token="svn.apache.org/viewvc/sis/trunk"
-                     value="svn.apache.org/viewvc/sis/branches/${branch.version}"/>
-    </replace>
-  </target>
-
-
-
-  <!-- Invoked after a tag has been created from the branch. -->
-  <target name="tag">
-
-    <!-- Replace URL to branch by URL to the branch on Subversion. -->
-    <replace dir="${user.dir}" failOnNoReplacements="true">
-      <include name="**/pom.xml"/>
-      <replacefilter token="svn.apache.org/repos/asf/sis/branches/${branch.version}"
-                     value="svn.apache.org/repos/asf/sis/tags/${sis.version}"/>
-      <replacefilter token="svn.apache.org/viewvc/sis/branches/${branch.version}"
-                     value="svn.apache.org/viewvc/sis/tags/${sis.version}"/>
-    </replace>
-
     <!-- Replace version numbers. Note that no snapshot other than SIS can exist at this point. -->
     <replace dir="${user.dir}" failOnNoReplacements="true">
       <include name="**/pom.xml"/>
-      <replacefilter token="&lt;version&gt;${branch.version}-SNAPSHOT&lt;/version&gt;"
+      <replacefilter token="&lt;version&gt;${sis.version}-SNAPSHOT&lt;/version&gt;"
                      value="&lt;version&gt;${sis.version}&lt;/version&gt;"/>
     </replace>
   </target>
diff --git a/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Doclet.java b/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Doclet.java
index dce22e1..7fa4ec8 100644
--- a/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Doclet.java
+++ b/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Doclet.java
@@ -20,6 +20,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.function.Supplier;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.io.File;
@@ -34,7 +35,6 @@
 import jdk.javadoc.doclet.Doclet.Option;
 import jdk.javadoc.doclet.DocletEnvironment;
 import jdk.javadoc.doclet.StandardDoclet;
-import com.sun.source.util.DocTrees;
 
 
 /**
@@ -58,7 +58,7 @@
  * @since   0.5
  * @module
  */
-public final class Doclet extends StandardDoclet {
+public final class Doclet extends StandardDoclet implements Supplier<Reporter> {
     /**
      * The name of the SIS-specific stylesheet file.
      */
@@ -71,25 +71,8 @@
 
     /**
      * Where to report warnings, or {@code null} if unknown.
-     *
-     * @todo make package-private after {@link #workaround8201817} has been removed.
      */
-    public Reporter reporter;
-
-    /**
-     * Utility methods for locating the path of elements, or {@code null} if unknown.
-     *
-     * @todo make package-private after {@link #workaround8201817} has been removed.
-     */
-    public DocTrees trees;
-
-    /**
-     * Temporary Workaround for https://bugs.openjdk.java.net/browse/JDK-8201817
-     *
-     * @deprecated to be removed after we upgraded Apache SIS build requirement to JDK 11.
-     */
-    @Deprecated
-    public static Doclet workaround8201817;
+    private Reporter reporter;
 
     /**
      * Invoked by the Javadoc tools for instantiating the custom doclet.
@@ -107,7 +90,18 @@
     public void init(final Locale locale, final Reporter reporter) {
         super.init(locale, reporter);
         this.reporter = reporter;
-        workaround8201817 = this;
+    }
+
+    /**
+     * Returns the {@link Reporter} associated to this doclet environment.
+     * This method is hack for giving that information to the taglets. We have to use a standard Java interfaces
+     * because the class loader of this {@code Doclet} will not be the same than the {@link Taglet} class loader.
+     *
+     * @return implementation-dependent information to give to taglets.
+     */
+    @Override
+    public Reporter get() {
+        return reporter;
     }
 
     /**
@@ -156,7 +150,6 @@
      */
     @Override
     public boolean run(final DocletEnvironment environment) {
-        trees = environment.getDocTrees();
         final boolean success = super.run(environment);
         if (success && outputDirectory != null) try {
             final Path output = Paths.get(outputDirectory);
diff --git a/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Taglet.java b/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Taglet.java
index b55fafe..b7be2cf 100644
--- a/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Taglet.java
+++ b/core/sis-build-helper/src/main/java/org/apache/sis/internal/doclet/Taglet.java
@@ -25,11 +25,13 @@
 import javax.lang.model.element.Element;
 import jdk.javadoc.doclet.DocletEnvironment;
 import jdk.javadoc.doclet.Reporter;
+import jdk.javadoc.doclet.Doclet;
 import com.sun.source.util.DocTrees;
 import com.sun.source.util.TreePath;
 import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.TextTree;
 import com.sun.source.doctree.UnknownInlineTagTree;
+import java.util.function.Supplier;
 
 
 /**
@@ -70,24 +72,9 @@
      * @param doclet  the doclet that instantiated this taglet.
      */
     @Override
-    public void init(final DocletEnvironment env, final jdk.javadoc.doclet.Doclet doclet) {
-        if (doclet instanceof Doclet) {
-            reporter = ((Doclet) doclet).reporter;
-            trees    = ((Doclet) doclet).trees;
-        } else {
-            // Temporary workaround for https://bugs.openjdk.java.net/browse/JDK-8201817
-            StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(stream ->
-                stream.filter(frame -> frame.getClassName().equals("org.apache.sis.internal.doclet.Doclet"))
-                      .map(frame -> frame.getDeclaringClass()).findFirst()).ifPresent(docletClass -> {
-                          try {
-                              Object instance = docletClass.getDeclaredField("workaround8201817").get(null);
-                              reporter = (Reporter) docletClass.getDeclaredField("reporter").get(instance);
-                              trees    = (DocTrees) docletClass.getDeclaredField("trees").get(instance);
-                          } catch (ReflectiveOperationException e) {
-                              printError("Unsupported doclet implementation. Caused by: " + e);
-                          }
-                      });
-        }
+    public void init(final DocletEnvironment env, final Doclet doclet) {
+        reporter = (Reporter) ((Supplier<?>) doclet).get();
+        trees = env.getDocTrees();
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/SequenceType.java b/core/sis-feature/src/main/java/org/apache/sis/image/SequenceType.java
index 8e42823..241d372 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/SequenceType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/SequenceType.java
@@ -21,8 +21,11 @@
  * Placeholder for {@code org.opengis.coverage.grid.SequenceType}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 1.1
+ *
+ * @see <a href="http://docs.opengeospatial.org/is/09-026r2/09-026r2.html">OGC® Filter Encoding 2.0 Encoding Standard</a>
+ *
+ * @since 1.1
  * @module
  */
 enum SequenceType {
diff --git a/core/sis-referencing-by-identifiers/pom.xml b/core/sis-referencing-by-identifiers/pom.xml
index 9410fba..efe20e3 100644
--- a/core/sis-referencing-by-identifiers/pom.xml
+++ b/core/sis-referencing-by-identifiers/pom.xml
@@ -112,6 +112,10 @@
       <artifactId>sis-referencing</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>jakarta.xml.bind</groupId>
+      <artifactId>jakarta.xml.bind-api</artifactId>
+    </dependency>
 
     <!-- Test dependencies -->
     <dependency>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
index e608226..7132271 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
@@ -1049,7 +1049,7 @@
             case IGNORE_METADATA: return equals(m1, m2, 0, false);
             case DEBUG:           // Fall through
             case ALLOW_VARIANT:   // Fall through
-            case APPROXIMATE:   return equals(m1, m2, Numerics.COMPARISON_THRESHOLD, true);
+            case APPROXIMATE:     return equals(m1, m2, Numerics.COMPARISON_THRESHOLD, true);
             default: throw new IllegalArgumentException(Errors.format(
                     Errors.Keys.UnknownEnumValue_2, ComparisonMode.class, mode));
         }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
index 1393b05..1aa0ff7 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
@@ -145,20 +145,24 @@
 
        <pre>mvn install -Dorg.apache.sis.test.extensive=true</pre></li>
 
-      <li><p>Upgrade the <code>FACTORY.VERSION</code> value defined in the
-          <code>org.apache.sis.referencing.report.CoordinateReferenceSystems</code> class, then execute that class.
-          It can be executed from the IDE since the <code>main</code> method takes no argument.
-          This class will write a <code>CoordinateReferenceSystems.html</code> file in current directory
-          (the full path will be printed in the standard output).
-          That file should be moved to the <code>site/content/tables/</code> directory,
-          where <code>site</code> is the directory containing a local checkout of
-          <a href="http://svn.apache.org/repos/asf/sis/site/trunk">http://svn.apache.org/repos/asf/sis/site/trunk</a>.</p></li>
+      <li><p>Regenerate the HTML pages listing available CRS and coordinate operation methods.
+          Those pages will be copied into the
+          <code><a href="http://svn.apache.org/repos/asf/sis/site/trunk/content/tables/">site/content/tables/</a></code>
+          directory during the <a href="http://sis.apache.org/release-management.html#update-crs-list">release process</a>,
+          but for now the purpose is only to check if there is errors:</p>
+        <ul>
+          <li><p>Upgrade the <code>FACTORY.VERSION</code> value defined in the
+              <code>org.apache.sis.referencing.report.CoordinateReferenceSystems</code> class, then execute that class.
+              It can be executed from the IDE since the <code>main</code> method takes no argument.
+              This class will write a <code>CoordinateReferenceSystems.html</code> file in current directory
+              (the full path will be printed in the standard output).</p></li>
 
-      <li><p>Execute the <code>org.apache.sis.referencing.report.CoordinateOperationMethods</code> class.
-          It can be executed from the IDE since the <code>main</code> method takes no argument.
-          This class will write a <code>CoordinateOperationMethods.html</code> file in current directory.
-          That file should be moved to the <code>site/content/tables/</code> directory,
-          where <code>site</code> is the directory than above.</p></li>
+          <li><p>Execute the <code>org.apache.sis.referencing.report.CoordinateOperationMethods</code> class.
+              It can be executed from the IDE since the <code>main</code> method takes no argument.
+              This class will write a <code>CoordinateOperationMethods.html</code> file in current directory.</p></li>
+        </ul>
+        <p>Open those generated HTML files in a web browser and verify the result.</p>
+      </li>
     </ol>
   </body>
 </html>
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/package-info.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/package-info.java
index 12ecd02..1ba2b7e 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/package-info.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/package-info.java
@@ -22,7 +22,7 @@
  * The reports are for example the list of all supported EPSG codes.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.7
  * @module
  */
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractConverter.java
index 4649573..a85e44d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractConverter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractConverter.java
@@ -140,7 +140,7 @@
     public UnitConverter concatenate(final UnitConverter converter) {
         ArgumentChecks.ensureNonNull("converter", converter);
         if (equals(converter.inverse())) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         return new ConcatenatedConverter(converter, this);
     }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/ConcatenatedConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/ConcatenatedConverter.java
index 18b4340..1569206 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/ConcatenatedConverter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/ConcatenatedConverter.java
@@ -126,7 +126,7 @@
     public UnitConverter concatenate(final UnitConverter converter) {
         ArgumentChecks.ensureNonNull("converter", converter);
         if (equals(converter.inverse())) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         // Delegate to c1 and c2 because they may provide more intelligent 'concatenate' implementations.
         return c2.concatenate(c1.concatenate(converter));
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java b/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
index 603a4ba..20cc956 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
@@ -310,7 +310,7 @@
     @Override
     public UnitConverter getConverterTo(final Unit<Q> that) throws UnconvertibleException {
         if (that == this) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         ArgumentChecks.ensureNonNull("that", that);
         UnitConverter c = toTarget;
@@ -340,7 +340,7 @@
     @Override
     public UnitConverter getConverterToAny(final Unit<?> that) throws IncommensurableException {
         if (that == this) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         ArgumentChecks.ensureNonNull("that", that);
         UnitConverter c = toTarget;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/IdentityConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/IdentityConverter.java
new file mode 100644
index 0000000..721342e
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/IdentityConverter.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.measure;
+
+import javax.measure.UnitConverter;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.LenientComparable;
+
+
+/**
+ * Linear converter with a scale factor of 1 and an offset of 0. We define a class for this special case
+ * instead than using the more generic {@link LinearConverter} class because we want to avoid performing
+ * any arithmetic operation in the {@link #convert(double)} method, in order to preserve negative zero:
+ *
+ * {@preformat java
+ *     convert(-0d) ≡ -0d
+ * }
+ *
+ * When the value is used in a map projection parameter, its sign can have implications in the chain of
+ * concatenated transforms. The final result is numerically equivalent, but intermediate steps may differ
+ * depending on the parameter sign.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+final class IdentityConverter extends AbstractConverter implements LenientComparable {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 1230536100139464866L;
+
+    /**
+     * The identity linear converter.
+     */
+    static final IdentityConverter INSTANCE = new IdentityConverter();
+
+    /**
+     * For {@link #INSTANCE} only.
+     */
+    private IdentityConverter() {
+    }
+
+    /** Straight forward implementation. */
+    @Override public boolean       isLinear()                   {return true;}
+    @Override public boolean       isIdentity()                 {return true;}
+    @Override public UnitConverter inverse()                    {return this;}
+    @Override public double        convert(double value)        {return value;}
+    @Override public double        derivative(double value)     {return 1;}
+    @Override public UnitConverter concatenate(UnitConverter c) {return c;}
+    @Override public String        toString()                   {return "y = x";}
+
+    /**
+     * Returns the value unchanged, with a check against null values
+     * for consistency with {@link LinearConverter#convert(Number)}.
+     */
+    @Override
+    public Number convert(Number value) {
+        ArgumentChecks.ensureNonNull("value", value);
+        return value;
+    }
+
+    /**
+     * Returns a hash code value for this unit converter.
+     */
+    @Override
+    public int hashCode() {
+        return (int) serialVersionUID;
+    }
+
+    /**
+     * Compares this converter with the given object for equality. This method may return {@code true}
+     * only if {@code Object} is an instance of {@link IdentityConverter} or {@link LinearConverter}.
+     * We apply this restriction in order to be symmetric with those cases,
+     * i.e. {@code A.equals(B)} = {@code B.equals(A)}.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        // See method javadoc for why we restrict to AbstractConverter instead of UnitConverter.
+        return (other instanceof AbstractConverter) && ((AbstractConverter) other).isIdentity();
+    }
+
+    /**
+     * Compares this converter with the given object for equality, optionally ignoring rounding errors.
+     */
+    @Override
+    public boolean equals(final Object other, final ComparisonMode mode) {
+        if (mode.isApproximate() && other instanceof LinearConverter) {
+            return ((LinearConverter) other).almostIdentity();
+        }
+        return (other instanceof UnitConverter) && ((UnitConverter) other).isIdentity();
+    }
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java b/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
index 75e7acd..dc81ec3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
@@ -53,11 +53,6 @@
     private static final long serialVersionUID = -3759983642723729926L;
 
     /**
-     * The identity linear converter.
-     */
-    static final LinearConverter IDENTITY = new LinearConverter(1, 0, 1);
-
-    /**
      * The scale to apply for converting values, before division by {@link #divisor}.
      */
     private final double scale;
@@ -101,7 +96,7 @@
      * Creates a linear converter from the given scale and offset, which may be {@link BigDecimal} instances.
      * This is the implementation of public {@link Units#converter(Number, Number)} method.
      */
-    static LinearConverter create(final Number scale, final Number offset) {
+    static AbstractConverter create(final Number scale, final Number offset) {
         final double numerator, divisor;
         double shift = (offset != null) ? doubleValue(offset) : 0;
         if (scale instanceof Fraction) {
@@ -112,21 +107,16 @@
             numerator = (scale != null) ? doubleValue(scale) : 1;
             divisor   = 1;
         }
-        final LinearConverter c = create(numerator, shift, divisor);
+        if (shift == 0 && numerator == divisor) {
+            return IdentityConverter.INSTANCE;
+        }
+        final LinearConverter c = new LinearConverter(numerator, shift, divisor);
         if (scale  instanceof BigDecimal) c.scale10  = (BigDecimal) scale;
         if (offset instanceof BigDecimal) c.offset10 = (BigDecimal) offset;
         return c;
     }
 
     /**
-     * Returns a linear converter for the given scale and offset.
-     */
-    private static LinearConverter create(final double scale, final double offset, final double divisor) {
-        if (offset == 0 && scale == divisor) return IDENTITY;
-        return new LinearConverter(scale, offset, divisor);
-    }
-
-    /**
      * Returns a linear converter for the given ratio. The scale factor is specified as a ratio because
      * the unit conversion factors are often defined with a value in base 10.  That value is considered
      * exact by definition, but IEEE 754 has no exact representation of decimal fraction digits.
@@ -171,7 +161,7 @@
             denominator = lc.divisor;
         } else {
             // Subtraction by convert(0) is a paranoiac safety.
-            numerator   = converter.convert(1.0) - converter.convert(0.0);
+            numerator   = converter.convert(1d) - converter.convert(0d);
             denominator = 1;
         }
         if (root) {
@@ -221,6 +211,13 @@
     }
 
     /**
+     * Returns {@code true} if this converter is close to an identity converter.
+     */
+    final boolean almostIdentity() {
+        return epsilonEquals(scale, divisor) && epsilonEquals(offset, 0);
+    }
+
+    /**
      * Returns the inverse of this unit converter.
      * Given that the formula applied by this converter is:
      *
@@ -248,7 +245,7 @@
      */
     @Override
     @SuppressWarnings("fallthrough")
-    Number[] coefficients() {
+    final Number[] coefficients() {
         final Number[] c = new Number[(scale != divisor) ? 2 : (offset != 0) ? 1 : 0];
         switch (c.length) {
             case 2: c[1] = ratio(scale,  divisor);
@@ -385,7 +382,10 @@
             otherOffset  /= cf;
             otherDivisor /= cf;
         }
-        return create(otherScale, otherOffset, otherDivisor);
+        if (otherOffset == 0 && otherScale == otherDivisor) {
+            return IdentityConverter.INSTANCE;
+        }
+        return new LinearConverter(otherScale, otherOffset, otherDivisor);
     }
 
     /**
@@ -409,6 +409,9 @@
                    Numerics.equals(offset,  o.offset) &&
                    Numerics.equals(divisor, o.divisor);
         }
+        if (other instanceof IdentityConverter) {
+            return isIdentity();
+        }
         return false;
     }
 
@@ -418,7 +421,13 @@
     @Override
     public boolean equals(final Object other, final ComparisonMode mode) {
         if (mode.isApproximate()) {
-            return (other instanceof LinearConverter) && equivalent((LinearConverter) other);
+            if (other instanceof LinearConverter) {
+                return equivalent((LinearConverter) other);
+            } else if (other instanceof IdentityConverter) {
+                return almostIdentity();
+            } else {
+                return false;
+            }
         } else {
             return equals(other);
         }
@@ -428,7 +437,7 @@
      * Returns {@code true} if the given converter perform the same conversion than this converter,
      * except for rounding errors.
      */
-    boolean equivalent(final LinearConverter other) {
+    final boolean equivalent(final LinearConverter other) {
         return epsilonEquals(scale  * other.divisor, other.scale  * divisor) &&
                epsilonEquals(offset * other.divisor, other.offset * divisor);
     }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java b/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
index d7caac0..fdaa50d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
@@ -359,7 +359,7 @@
             throw new UnconvertibleException(incompatible(unit));
         }
         if (step == unit) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         /*
          * At this point we know that the given units is not a system unit. Ask the conversion
@@ -389,7 +389,7 @@
             throw new IncommensurableException(incompatible(unit));
         }
         if (step == unit) {
-            return LinearConverter.IDENTITY;
+            return IdentityConverter.INSTANCE;
         }
         // Same remark than in getConverterTo(Unit).
         return unit.getConverterToAny(step).inverse();
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
index 2381eff..d4800d1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
@@ -1329,7 +1329,7 @@
      * This method shall be invoked in a single thread by the {@code Units} class initializer only.
      *
      * <p>The {@code target} argument should be an instance of {@link SystemUnit}.
-     * The only exception is for creating the {@link DECIBEL} unit base on the bel conventional unit.</p>
+     * The only exception is for creating the {@link #DECIBEL} unit base on the bel conventional unit.</p>
      *
      * <p>If the {@code target} unit holds a list of {@linkplain SystemUnit#related() related units}
      * (i.e. conventional units that can not be computed easily by appending a SI prefix), then the new
diff --git a/core/sis-utility/src/main/java/org/apache/sis/setup/Configuration.java b/core/sis-utility/src/main/java/org/apache/sis/setup/Configuration.java
index a27973d..964de1d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/setup/Configuration.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/setup/Configuration.java
@@ -86,14 +86,32 @@
     /**
      * Specifies the data source to use if no {@code "jdbc/SpatialMetadata"} source is binded to a JNDI environment.
      * Data source specified by JNDI has precedence over data source specified by this method in order to let users
-     * control their data source.
+     * control their data source. The following example shows how to setup a connection to a PostgreSQL database:
      *
-     * <p>This method can be invoked only before the first attempt to {@linkplain #getDatabase() get the database}.
-     * If the {@link DataSource} has already be obtained, then this method throws {@link IllegalStateException}.</p>
+     * {@preformat java
+     *     import org.postgresql.ds.PGSimpleDataSource;
+     *
+     *     // Class and method declarations omitted for brevity.
+     *     PGSimpleDataSource ds = new PGSimpleDataSource();
+     *     ds.setServerName("localhost");
+     *     ds.setDatabaseName("SpatialMetadata");
+     *
+     *     // Registration assuming that a JNDI implementation is available
+     *     Context env = (Context) InitialContext.doLookup("java:comp/env");
+     *     env.bind("jdbc/SpatialMetadata", ds);
+     *
+     *     // Registration without JNDI.
+     *     Configuration.current().setDatabase(() -> ds);
+     * }
+     *
+     * This method can be invoked only before the first attempt to {@linkplain #getDatabase() get the database}.
+     * If the {@link DataSource} has already be obtained, then this method throws {@link IllegalStateException}.
      *
      * @param  source  supplier of data source to set.
      *         The supplier may return {@code null}, in which case it will be ignored.
      * @throws IllegalStateException if {@link DataSource} has already be obtained before this method call.
+     *
+     * @see <a href="http://sis.apache.org/epsg.html#jndi">How to use EPSG geodetic dataset</a>
      */
     public void setDatabase(final Supplier<DataSource> source) {
         ArgumentChecks.ensureNonNull("source", source);
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/LinearConverterTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/LinearConverterTest.java
index c4b3ca0..d8138ce 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/LinearConverterTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/LinearConverterTest.java
@@ -43,7 +43,7 @@
      * @param  denominator  the expected denominator in the conversion factor.
      * @param  converter    the converter to verify.
      */
-    static void assertScale(final int numerator, final int denominator, final LinearConverter converter) {
+    static void assertScale(final int numerator, final int denominator, final AbstractConverter converter) {
         final double derivative = numerator / (double) denominator;
         final Number[] coefficients = converter.coefficients();
         assertEquals("coefficients.length", 2, coefficients.length);
@@ -88,7 +88,7 @@
      */
     @Test
     public void testIsIdentityAndLinear() {
-        LinearConverter c = LinearConverter.IDENTITY;
+        AbstractConverter c = IdentityConverter.INSTANCE;
         assertTrue(c.isIdentity());
         assertTrue(c.isLinear());
         assertEquals("coefficients.length", 0, c.coefficients().length);
@@ -185,15 +185,15 @@
      */
     @Test
     public void testConcatenate() {
-        LinearConverter c = LinearConverter.scale(254, 100);                        // inches to centimetres
+        AbstractConverter c = LinearConverter.scale(254, 100);                      // inches to centimetres
         assertScale(254, 100, c);
-        c = (LinearConverter) c.concatenate(LinearConverter.scale(10, 1));          // centimetres to millimetres
+        c = (AbstractConverter) c.concatenate(LinearConverter.scale(10, 1));        // centimetres to millimetres
         assertScale(254, 10, c);
-        c = (LinearConverter) c.concatenate(LinearConverter.scale(1, 1000));        // millimetres to metres
+        c = (AbstractConverter) c.concatenate(LinearConverter.scale(1, 1000));      // millimetres to metres
         assertScale(254, 10000, c);
 
         c = LinearConverter.offset(27315, 100);                                     // Celsius to kelvin
-        c = (LinearConverter) c.concatenate(LinearConverter.offset(-54630, 200));
+        c = (AbstractConverter) c.concatenate(LinearConverter.offset(-54630, 200));
         assertTrue(c.isIdentity());
     }
 
@@ -228,7 +228,7 @@
      */
     @Test
     public void testToString() {
-        assertEquals("y = x",                   LinearConverter.IDENTITY          .toString());
+        assertEquals("y = x",                   IdentityConverter.INSTANCE        .toString());
         assertEquals("y = 100⋅x",               LinearConverter.scale (  100,   1).toString());
         assertEquals("y = x∕100",               LinearConverter.scale (    1, 100).toString());
         assertEquals("y = 254⋅x∕100",           LinearConverter.scale (  254, 100).toString());
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/QuantitiesTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/QuantitiesTest.java
index 5d726d2..bfab6bf 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/QuantitiesTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/QuantitiesTest.java
@@ -110,4 +110,21 @@
         r = q1.multiply(1);
         assertSame(q1, r);
     }
+
+    /**
+     * Tests {@link Scalar#equals(Object)} and {@link Scalar#hashCode()}.
+     * This test uses a unit without specific {@link Scalar} subclass, in order to
+     * verify that tested methods work even though the {@link ScalarFallback} proxy.
+     */
+    @Test
+    public void testEqualsAndHashcode() {
+        Quantity<?> q1 = Quantities.create(2, Units.VOLT);
+        Quantity<?> q2 = Quantities.create(2, Units.VOLT);
+        Quantity<?> q3 = Quantities.create(3, Units.VOLT);
+        assertTrue (q1.hashCode() == q2.hashCode());
+        assertFalse(q1.hashCode() == q3.hashCode());
+        assertTrue (q1.hashCode() != 0);
+        assertTrue (q1.equals(q2));
+        assertFalse(q1.equals(q3));
+    }
 }
diff --git a/ide-project/NetBeans/nbproject/project.properties b/ide-project/NetBeans/nbproject/project.properties
index a91ab13..0b1421b 100644
--- a/ide-project/NetBeans/nbproject/project.properties
+++ b/ide-project/NetBeans/nbproject/project.properties
@@ -110,7 +110,7 @@
 rome.version         = 0.9
 jdom1.version        = 1.0
 jdom2.version        = 2.0.4
-jee.version          = 8.0
+jee.version          = 8.0.1
 osgi.version         = 6.0.0
 netcdf.version       = 4.6.14
 joda-time.version    = 2.8.1
diff --git a/pom.xml b/pom.xml
index f73ce66..44eaa62 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
      Maven 2 project configuration file
      http://maven.apache.org/maven2/
 
-     Apache SIS build requires Java 10 or higher, but compiled files can be executed on Java 8.
+     Apache SIS build requires Java 11 or higher, but compiled files can be executed on Java 8.
      Setting the SIS_DATA environment variable before build is optional but recommended.
 
      Build development snapshot:    mvn clean install
@@ -560,7 +560,7 @@
     <maven.compiler.source>8</maven.compiler.source>
     <maven.compiler.target>8</maven.compiler.target>
     <sis.plugin.version>${project.version}</sis.plugin.version>
-    <sis.non-free.version>1.0-M1</sis.non-free.version>                 <!-- Used only if "non-free" profile is enabled. -->
+    <sis.non-free.version>1.0</sis.non-free.version>                 <!-- Used only if "non-free" profile is enabled. -->
     <geoapi.version>3.0.1</geoapi.version>
     <jaxb.version>2.3.2</jaxb.version>
   </properties>
@@ -624,7 +624,7 @@
             <configuration>
               <rules>
                 <requireJavaVersion>
-                  <version>10</version>
+                  <version>11</version>
                 </requireJavaVersion>
               </rules>
             </configuration>
@@ -873,6 +873,7 @@
 
           <additionalOptions>
             <additionalOption>--add-stylesheet "${maven.multiModuleProjectDirectory}/src/main/javadoc/sis.css"</additionalOption>
+            <additionalOption>--no-module-directories</additionalOption> <!-- https://bugs.openjdk.java.net/browse/JDK-8215291 -->
           </additionalOptions>
 
           <!-- Separates packages on the overview page into the groups specified. -->
@@ -920,8 +921,6 @@
 
           <!-- Custom taglets, some of them implemented in Java. -->
           <tags>
-            <tag><placement>t</placement> <name>goal</name>     <head>Maven goal:</head></tag>
-            <tag><placement>t</placement> <name>phase</name>    <head>Maven phase:</head></tag>
             <tag><placement>X</placement> <name>category</name> <head>Category:</head></tag>
             <tag><placement>a</placement> <name>todo</name>     <head>TODO:</head></tag>
           </tags>
diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/profile/japan/JapaneseProfile.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/profile/japan/JapaneseProfile.java
new file mode 100644
index 0000000..84b6c05
--- /dev/null
+++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/profile/japan/JapaneseProfile.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.profile.japan;
+
+import org.apache.sis.util.Static;
+
+
+/**
+ * Provides implementations of Japanese extensions.
+ * There is not yet public methods provided in this class.
+ * Just having this module presents on the classpath is sufficient for enabling the reading of following data:
+ *
+ * <ul>
+ *   <li>Global Change Observation Mission - Climate (GCOM-C), a.k.a. "Shikisai".</li>
+ *   <li>Global Change Observation Mission - Water (GCOM-W), a.k.a. "Shizuku".</li>
+ * </ul>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+public final class JapaneseProfile extends Static {
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private JapaneseProfile() {
+    }
+}
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java
index e377c97..098680e 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java
@@ -26,8 +26,8 @@
  * be controlled by options, which may be {@link DataStore}-specific.
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 1.1
+ * @since   1.1
  * @module
  */
 public interface WritableGridCoverageResource extends GridCoverageResource {