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

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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 6b2e63471f     Upgrade JSR-363 dependency to JSR-385.     This is the 
dependency that defines unit of measurements in the `javax.measure` package.
6b2e63471f is described below

commit 6b2e63471fc87b98cfa312090f6c6c833a943dfe
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Dec 26 17:32:07 2022 +0100

        Upgrade JSR-363 dependency to JSR-385.
        This is the dependency that defines unit of measurements in the 
`javax.measure` package.
    
        https://github.com/opengeospatial/geoapi/issues/66
---
 NOTICE                                             |   4 +-
 README                                             |   2 +-
 .../java/org/apache/sis/xml/ValueConverter.java    |   4 +-
 .../java/org/apache/sis/io/wkt/AbstractParser.java |   4 +-
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |   4 +-
 .../org/apache/sis/io/wkt/MathTransformParser.java |   4 +-
 .../referencing/factory/sql/EPSGDataAccess.java    |   4 +-
 .../sis/internal/converter/StringConverter.java    |   4 +-
 .../java/org/apache/sis/io/CompoundFormat.java     |   2 +-
 .../org/apache/sis/measure/AbstractConverter.java  |   8 +-
 .../java/org/apache/sis/measure/AbstractUnit.java  |  86 +++++++++++++++-
 .../org/apache/sis/measure/ConventionalUnit.java   |  10 +-
 .../apache/sis/measure/DefaultQuantityFactory.java |  75 ++++++++++++++
 .../org/apache/sis/measure/LinearConverter.java    |   8 +-
 .../java/org/apache/sis/measure/Quantities.java    |   4 +-
 .../org/apache/sis/measure/QuantityFormat.java     | 110 ++++++++++++++++++++-
 .../main/java/org/apache/sis/measure/Scalar.java   |  53 +++++++++-
 .../java/org/apache/sis/measure/SystemUnit.java    |  18 +++-
 .../java/org/apache/sis/measure/UnitFormat.java    |  44 +++++----
 .../java/org/apache/sis/measure/UnitRegistry.java  |  25 ++++-
 .../java/org/apache/sis/measure/UnitServices.java  |  83 +++++++++++-----
 .../main/java/org/apache/sis/measure/Units.java    |   8 +-
 .../java/org/apache/sis/measure/package-info.java  |   2 +-
 .../org/apache/sis/measure/QuantitiesTest.java     |   5 +-
 .../org/apache/sis/measure/SystemUnitTest.java     |   4 +-
 .../org/apache/sis/measure/UnitDimensionTest.java  |   4 +-
 .../org/apache/sis/measure/UnitFormatTest.java     |  12 +--
 .../org/apache/sis/measure/UnitServicesTest.java   |  13 +--
 ide-project/NetBeans/nbproject/project.properties  |   4 +-
 .../apache/sis/internal/earth/netcdf/GCOM_C.java   |   6 +-
 .../apache/sis/internal/earth/netcdf/GCOM_W.java   |   6 +-
 .../org/apache/sis/internal/netcdf/Convention.java |   6 +-
 .../org/apache/sis/internal/netcdf/Variable.java   |   4 +-
 .../sis/internal/netcdf/impl/ChannelDecoder.java   |   4 +-
 .../sis/internal/netcdf/impl/VariableInfo.java     |   6 +-
 .../apache/sis/storage/netcdf/MetadataReader.java  |   6 +-
 36 files changed, 518 insertions(+), 128 deletions(-)

diff --git a/NOTICE b/NOTICE
index 888bab1447..80a7402733 100644
--- a/NOTICE
+++ b/NOTICE
@@ -10,8 +10,8 @@ specifications (https://www.ogc.org/standards/), also known 
as OpenGIS.
 Apache SIS depends on GeoAPI published by OGC under BSD-style license.
 https://www.ogc.org/ogc/software/1.0
 
-Apache SIS depends on JSR-363 (API only) published under BSD license.
-https://jcp.org/en/jsr/detail?id=363
+Apache SIS depends on JSR-385 (API only) published under BSD license.
+https://jcp.org/en/jsr/detail?id=385
 
 Apache SIS depends on JAXB (API only) published under Eclipse Distribution 
License license.
 http://www.eclipse.org/org/documents/edl-v10.php
diff --git a/README b/README
index d617b55a6d..6d6ccb228f 100644
--- a/README
+++ b/README
@@ -57,7 +57,7 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 
 Some Apache SIS subcomponents have dependencies subject to different
-license terms. All those dependencies except GeoAPI, JSR-363 and JAXB API
+license terms. All those dependencies except GeoAPI, JSR-385 and JAXB API
 are optional. Your use of those dependencies is subject to the terms and
 conditions of the licenses listed in the NOTICE file.
 
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java 
b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
index 72404ba57e..895f00fb99 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
@@ -27,7 +27,7 @@ import java.util.UUID;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.Locales;
@@ -356,7 +356,7 @@ public class ValueConverter {
                 }
             }
             return Units.valueOf(value);
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             if (!exceptionOccured(context, value, String.class, Unit.class, 
e)) {
                 throw e;
             }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/AbstractParser.java 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
index 9ac37aa939..bbcf6b9344 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
@@ -30,7 +30,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.system.Loggers;
@@ -388,7 +388,7 @@ abstract class AbstractParser implements Parser {
      * Parses the given unit name or symbol. Contrarily to other {@code 
parseFoo()} methods,
      * this method has no {@link ParsePosition} and expects the given string 
to be the full unit symbol.
      */
-    final Unit<?> parseUnit(final String text) throws ParserException {
+    final Unit<?> parseUnit(final String text) throws 
MeasurementParseException {
         if (unitFormat == null) {
             final Locale locale = symbols.getLocale();
             if (locale == Locale.ROOT) {
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
index 8185465657..f3aa4afcf8 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -37,7 +37,7 @@ import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
 import javax.measure.Quantity;
 import javax.measure.quantity.Time;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import javax.measure.IncommensurableException;
 
 import org.opengis.metadata.Identifier;
@@ -638,7 +638,7 @@ class GeodeticObjectParser extends MathTransformParser 
implements Comparator<Coo
         if (verify == null) {
             try {
                 verify = parseUnit(name);
-            } catch (ParserException e) {
+            } catch (MeasurementParseException e) {
                 log(new LogRecord(Level.FINE, e.toString()));
             }
             if (verify != null) try {
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
index 6a1c697638..be1eed1c03 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
@@ -24,7 +24,7 @@ import java.text.NumberFormat;
 import java.text.ParseException;
 import javax.measure.Unit;
 import javax.measure.quantity.Angle;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.parameter.ParameterValue;
@@ -285,7 +285,7 @@ class MathTransformParser extends AbstractParser {
         // If we cannot infer the base type, we have to rely on the name.
         try {
             return parseUnit(name);
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             throw new UnparsableObjectException(errorLocale, 
Errors.Keys.UnknownUnit_1,
                     new Object[] {name}, element.offset).initCause(e);
         }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 0730a71e19..f9a24349b0 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -45,7 +45,7 @@ import java.net.URISyntaxException;
 import javax.measure.Unit;
 import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 
 import org.opengis.util.NameSpace;
 import org.opengis.util.GenericName;
@@ -2489,7 +2489,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                         unit = Units.multiply(base, b, c);
                     } else try {
                         unit = Units.valueOf(getString(code, result, 5));      
     // Try parsing the unit symbol as a fallback.
-                    } catch (ParserException e) {
+                    } catch (MeasurementParseException e) {
                         throw new 
FactoryDataException(error().getString(Errors.Keys.UnknownUnit_1, code), e);
                     }
                 }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
 
b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
index 0f8b663c54..7c694b6416 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
@@ -23,7 +23,7 @@ import java.nio.charset.UnsupportedCharsetException;
 import java.net.URISyntaxException;
 import java.net.MalformedURLException;
 import java.nio.file.InvalidPathException;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.math.FunctionProperty;
 import org.apache.sis.util.Locales;
 import org.apache.sis.util.Numbers;
@@ -307,7 +307,7 @@ abstract class StringConverter<T> extends 
SystemConverter<String, T> {
         @SuppressWarnings("unchecked")
         public Unit() {super((Class) javax.measure.Unit.class);}               
// Instantiated by ServiceLoader.
 
-        @Override javax.measure.Unit<?> doConvert(String source) throws 
ParserException {
+        @Override javax.measure.Unit<?> doConvert(String source) throws 
MeasurementParseException {
             return Units.valueOf(source);
         }
     }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java 
b/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
index bf249b7ec6..4774db51ac 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
@@ -407,7 +407,7 @@ public abstract class CompoundFormat<T> extends Format 
implements Localized {
                  * We tried the given class directly. If it didn't worked, try 
the interfaces before
                  * to try the parent class. The reason is that we may have for 
example:
                  *
-                 *     interface Length extends Quantity;                   // 
From JSR-363.
+                 *     interface Length extends Quantity;                   // 
From JSR-385.
                  *
                  *     class MyLength extends Number implements Length;
                  *
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 bffbb99d93..3b60184506 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
@@ -54,7 +54,7 @@ abstract class AbstractConverter implements UnitConverter, 
Serializable {
     }
 
     /**
-     * Indicates if this converter is linear in JSR-363 sense (not the usual 
mathematical sense).
+     * Indicates if this converter is linear in JSR-385 sense (not the usual 
mathematical sense).
      * The default implementation returns {@code false} for convenience of 
non-linear conversions.
      * Subclasses should override if their conversions may be identity.
      */
@@ -109,8 +109,10 @@ abstract class AbstractConverter implements UnitConverter, 
Serializable {
      */
     static double scale(final UnitConverter converter) {
         if (converter != null && converter.isLinear() && converter.convert(0) 
== 0) {
-            // Above check for converter(0) is a paranoiac check since
-            // JSR-363 said that a "linear" converter has no offset.
+            /*
+             * Above check for `converter(0)` is a paranoiac check because
+             * JSR-385 said that a "linear" converter has no offset.
+             */
             return converter.convert(1);
         }
         return Double.NaN;
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
index 357d56d8ed..b623ade23b 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
@@ -23,10 +23,11 @@ import java.util.MissingResourceException;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
 import javax.measure.Unit;
+import javax.measure.Prefix;
 import javax.measure.Quantity;
 import org.apache.sis.math.Fraction;
+import org.apache.sis.math.MathFunctions;
 import org.apache.sis.util.Characters;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.LenientComparable;
 import org.apache.sis.util.resources.Errors;
@@ -57,7 +58,7 @@ import static java.util.logging.Logger.getLogger;
  * All unit instances shall be immutable and thread-safe.
  *
  * @author  Martin Desruisseaux (MPO, Geomatys)
- * @version 1.0
+ * @version 1.4
  *
  * @param <Q>  the kind of quantity to be measured using this units.
  *
@@ -348,10 +349,20 @@ abstract class AbstractUnit<Q extends Quantity<Q>> 
implements Unit<Q>, LenientCo
      */
     @Override
     public final boolean isCompatible(final Unit<?> that) {
-        ArgumentChecks.ensureNonNull("that", that);
         return getDimension().equals(that.getDimension());
     }
 
+    /**
+     * Indicates if this unit is equal to the given unit, ignoring unit symbol.
+     *
+     * @param  that the other unit to compare for equivalence.
+     * @return {@code true} if the given unit is equivalent to this unit.
+     */
+    @Override
+    public final boolean isEquivalentTo(final Unit<Q> that) {
+        return getConverterTo(that).isIdentity();
+    }
+
     /**
      * Returns the error message for an incompatible unit.
      */
@@ -359,6 +370,75 @@ abstract class AbstractUnit<Q extends Quantity<Q>> 
implements Unit<Q>, LenientCo
         return Errors.format(Errors.Keys.IncompatibleUnits_2, this, that);
     }
 
+    /**
+     * Returns a new unit equals to this unit prefixed by the specified {@code 
prefix}.
+     *
+     * @param  prefix  the prefix to apply on this unit.
+     * @return the unit with the given prefix applied.
+     */
+    @Override
+    public final Unit<Q> prefix(final Prefix prefix) {
+        final Number base = prefix.getValue();
+        final int exponent = prefix.getExponent();
+        if (exponent == 1) {
+            return multiply(base);
+        }
+        double value = AbstractConverter.doubleValue(base);
+        if (value == 10) {
+            value = MathFunctions.pow10(exponent);      // Avoid rounding 
errors for some values.
+        } else {
+            value = Math.pow(value, exponent);
+        }
+        return multiply(value);
+    }
+
+    /**
+     * Returns the result of setting the origin of the scale of measurement to 
the given value.
+     *
+     * @param  offset  the value to add when converting from the new unit to 
this unit.
+     * @return this unit offset by the specified value, or {@code this} if the 
given offset is zero.
+     */
+    @Override
+    public final Unit<Q> shift(final Number offset) {
+        if (offset instanceof Fraction) {
+            final Fraction f = (Fraction) offset;
+            return transform(LinearConverter.offset(f.numerator, 
f.denominator));
+        }
+        return shift(AbstractConverter.doubleValue(offset));
+    }
+
+    /**
+     * Returns the result of multiplying this unit by the specified factor.
+     * For example {@code KILOMETRE = METRE.multiply(1000)} returns a unit 
where 1 km is equal to 1000 m.
+     *
+     * @param  multiplier  the scale factor when converting from the new unit 
to this unit.
+     * @return this unit scaled by the specified multiplier.
+     */
+    @Override
+    public final Unit<Q> multiply(final Number multiplier) {
+        if (multiplier instanceof Fraction) {
+            final Fraction f = (Fraction) multiplier;
+            return transform(LinearConverter.scale(f.numerator, 
f.denominator));
+        }
+        return multiply(AbstractConverter.doubleValue(multiplier));
+    }
+
+    /**
+     * Returns the result of dividing this unit by an approximate divisor.
+     * For example {@code GRAM = KILOGRAM.divide(1000)} returns a unit where 1 
g is equal to 0.001 kg.
+     *
+     * @param  divisor  the inverse of the scale factor when converting from 
the new unit to this unit.
+     * @return this unit divided by the specified divisor.
+     */
+    @Override
+    public final Unit<Q> divide(final Number divisor) {
+        if (divisor instanceof Fraction) {
+            final Fraction f = (Fraction) divisor;
+            return transform(LinearConverter.scale(f.denominator, 
f.numerator));
+        }
+        return divide(AbstractConverter.doubleValue(divisor));
+    }
+
     /**
      * Returns the result of setting the origin of the scale of measurement to 
the given value.
      * For example, {@code CELSIUS = KELVIN.shift(273.15)} returns a unit 
where 0°C is equal to 273.15 K.
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 19f645f80d..0b2afa4fec 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
@@ -21,6 +21,7 @@ import javax.measure.Unit;
 import javax.measure.Quantity;
 import javax.measure.Dimension;
 import javax.measure.UnitConverter;
+import javax.measure.MeasurementException;
 import javax.measure.UnconvertibleException;
 import javax.measure.IncommensurableException;
 import org.apache.sis.util.resources.Errors;
@@ -35,7 +36,7 @@ import org.apache.sis.math.Fraction;
  * A unit of measure which is related to a base or derived unit through a 
conversion formula.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.4
  *
  * @param <Q>  the kind of quantity to be measured using this units.
  *
@@ -59,6 +60,7 @@ final class ConventionalUnit<Q extends Quantity<Q>> extends 
AbstractUnit<Q> {
     /**
      * The conversion from this unit to the {@linkplain #target} unit.
      */
+    @SuppressWarnings("serial")         // Not statically typed as 
Serializable.
     final UnitConverter toTarget;
 
     /**
@@ -371,17 +373,17 @@ final class ConventionalUnit<Q extends Quantity<Q>> 
extends AbstractUnit<Q> {
     }
 
     /**
-     * Unsupported operation for conventional units, as required by JSR-363 
specification.
+     * Unsupported operation for conventional units, as required by JSR-385 
specification.
      *
      * @param  symbol  the new symbol for the alternate unit.
      * @return the alternate unit.
-     * @throws UnsupportedOperationException always thrown since this unit is 
not an unscaled standard unit.
+     * @throws MeasurementException always thrown because this unit is not an 
unscaled standard unit.
      *
      * @see SystemUnit#alternate(String)
      */
     @Override
     public Unit<Q> alternate(final String symbol) {
-        throw new 
UnsupportedOperationException(Errors.format(Errors.Keys.NonSystemUnit_1, this));
+        throw new 
MeasurementException(Errors.format(Errors.Keys.NonSystemUnit_1, this));
     }
 
     /**
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/DefaultQuantityFactory.java
 
b/core/sis-utility/src/main/java/org/apache/sis/measure/DefaultQuantityFactory.java
new file mode 100644
index 0000000000..915e151a72
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/measure/DefaultQuantityFactory.java
@@ -0,0 +1,75 @@
+/*
+ * 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 java.util.Objects;
+import javax.measure.Unit;
+import javax.measure.Quantity;
+import javax.measure.spi.QuantityFactory;
+
+
+/**
+ * Default factory when {@link SystemUnit} can not be used directly.
+ *
+ * @author  Martin Desruisseaux (MPO, Geomatys)
+ * @version 1.4
+ * @since   1.4
+ */
+class DefaultQuantityFactory<Q extends Quantity<Q>> implements 
QuantityFactory<Q> {
+    /**
+     * Creates a new factory.
+     */
+    DefaultQuantityFactory() {
+    }
+
+    /**
+     * Unconditionally returns {@code null} because this factory
+     * should be used only when the type is not for a system unit.
+     */
+    @Override
+    public final Unit<Q> getSystemUnit() {
+        return null;
+    }
+
+    /**
+     * Creates a quantity for the given number stated in the specified unit.
+     *
+     * @param  value  the numeric value stated in the specified unit.
+     * @param  unit   the unit of the value.
+     * @return the requested quantity.
+     */
+    @Override
+    public Quantity<Q> create(final Number value, final Unit<Q> unit) {
+        return new Scalar<>(AbstractConverter.doubleValue(value), unit);
+    }
+
+    /**
+     * Creates a quantity for the given number stated in the specified unit 
and scale.
+     *
+     * @param  value  the numeric value stated in the specified unit.
+     * @param  unit   the unit of the value.
+     * @param  scale  the {@code ABSOLUTE} / {@code RELATIVE} scale of the 
quantity to create.
+     * @return the requested quantity.
+     */
+    @Override
+    public final Quantity<Q> create(final Number value, final Unit<Q> unit, 
final Quantity.Scale scale) {
+        if (Objects.requireNonNull(scale) != Scalar.SCALE) {
+            throw new UnsupportedOperationException("Relative scale is not yet 
supported.");
+        }
+        return create(value, unit);
+    }
+}
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 a631cf9b0d..568291a246 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
@@ -31,7 +31,7 @@ import org.apache.sis.internal.util.Numerics;
 /**
  * Conversions between units that can be represented by a linear operation 
(scale or offset).
  * Note that the "linear" word in this class does not have the same meaning 
than the same word
- * in the {@link #isLinear()} method inherited from JSR-363.
+ * in the {@link #isLinear()} method inherited from JSR-385.
  *
  * <p><b>Implementation note:</b>
  * for performance reason we should create specialized subtypes for the case 
where there is only a scale to apply,
@@ -187,7 +187,7 @@ final class LinearConverter extends AbstractConverter 
implements LenientComparab
 
     /**
      * Indicates if this converter is linear.
-     * JSR-363 defines a converter as linear if:
+     * JSR-385 defines a converter as linear if:
      *
      * <ul>
      *   <li>{@code convert(u + v) == convert(u) + convert(v)}</li>
@@ -354,8 +354,8 @@ final class LinearConverter extends AbstractConverter 
implements LenientComparab
             otherDivisor = lc.divisor;
         } else if (converter.isLinear()) {
             /*
-             * Fallback for foreigner implementations. Note that 'otherOffset' 
should be restricted to zero
-             * according JSR-363 definition of 'isLinear()', but let be safe; 
maybe we are not the only one
+             * Fallback for foreigner implementations. Note that `otherOffset` 
should be restricted to zero
+             * according JSR-385 definition of `isLinear()`, but let be safe; 
maybe we are not the only one
              * to have a different interpretation about the meaning of 
"linear".
              */
             otherOffset  = converter.convert(0.0);
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
index 49a9d3b93e..90fe3d7cd5 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Quantities.java
@@ -24,7 +24,7 @@ import javax.measure.UnitConverter;
 import javax.measure.quantity.Time;
 import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArgumentChecks;
@@ -61,7 +61,7 @@ public final class Quantities extends Static {
      * @param  value  the quantity magnitude.
      * @param  unit   symbol of the unit of measurement associated to the 
given value.
      * @return a quantity of the given type for the given value and unit of 
measurement.
-     * @throws ParserException if the given symbol cannot be parsed.
+     * @throws MeasurementParseException if the given symbol cannot be parsed.
      */
     public static Quantity<?> create(final double value, final String unit) {
         return create(value, Units.valueOf(unit));
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
index 847156378e..875fa10e6f 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/QuantityFormat.java
@@ -21,11 +21,13 @@ import java.text.Format;
 import java.text.FieldPosition;
 import java.text.NumberFormat;
 import java.text.ParsePosition;
+import java.io.IOException;
 import javax.measure.Quantity;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.internal.util.FinalFieldSetter;
 
@@ -36,7 +38,7 @@ import static java.util.logging.Logger.getLogger;
  * Parses and formats numbers with units of measurement.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.4
  *
  * @see NumberFormat
  * @see UnitFormat
@@ -44,7 +46,7 @@ import static java.util.logging.Logger.getLogger;
  * @since 1.1
  * @module
  */
-public class QuantityFormat extends Format {
+public class QuantityFormat extends Format implements 
javax.measure.format.QuantityFormat {
     /**
      * For cross-version compatibility.
      */
@@ -90,6 +92,50 @@ public class QuantityFormat extends Format {
         this.unitFormat   = unitFormat;
     }
 
+    /**
+     * Returns whether this format depends on a {@code Locale} to perform its 
tasks.
+     * This is {@code true} in this {@code QuantityFormat} implementation.
+     *
+     * @return whether this format depends on the locale, which is true in 
this implementation.
+     * @since  1.4
+     */
+    @Override
+    public boolean isLocaleSensitive() {
+        return true;
+    }
+
+    /**
+     * Formats the specified quantity.
+     * The default implementation delegates to {@link #format(Object, 
StringBuffer, FieldPosition)}.
+     *
+     * @param  quantity  the quantity to format.
+     * @return the string representation of the given quantity.
+     * @since  1.4
+     */
+    @Override
+    public String format(final Quantity<?> quantity) {
+        return format(quantity, new StringBuffer(), null).toString();
+    }
+
+    /**
+     * Formats the specified quantity in the given destination.
+     * The default implementation delegates to {@link #format(Object, 
StringBuffer, FieldPosition)}.
+     *
+     * @param  quantity    the quantity to format.
+     * @param  toAppendTo  where to format the quantity.
+     * @return the given {@code toAppendTo} argument, for method calls 
chaining.
+     * @throws IOException if an I/O exception occurred.
+     * @since  1.4
+     */
+    @Override
+    public Appendable format(final Quantity<?> quantity, final Appendable 
toAppendTo) throws IOException {
+        if (toAppendTo instanceof StringBuffer) {
+            return format(quantity, (StringBuffer) toAppendTo, null);
+        } else {
+            return toAppendTo.append(format(quantity, new StringBuffer(), 
null));
+        }
+    }
+
     /**
      * Formats the specified quantity in the given buffer.
      * The given object shall be a {@link Quantity} instance.
@@ -108,6 +154,62 @@ public class QuantityFormat extends Format {
         return toAppendTo;
     }
 
+    /**
+     * Parses the specified text to produce a {@link Quantity}.
+     *
+     * @param  source  the text to parse.
+     * @return the quantity parsed from the specified text.
+     * @throws MeasurementParseException if the given text can not be parsed.
+     * @since  1.4
+     */
+    @Override
+    public Quantity<?> parse(final CharSequence source) throws 
MeasurementParseException {
+        return parse(source, new ParsePosition(0));
+    }
+
+    /**
+     * Parses a portion of the specified {@code CharSequence} from the 
specified position to produce a {@link Quantity}.
+     * If parsing succeeds, then the index of the {@code pos} argument is 
updated to the index after the last character used.
+     *
+     * @param  source  the text, part of which should be parsed.
+     * @param  pos     index and error index information.
+     * @return the quantity parsed from the specified character sub-sequence.
+     * @throws MeasurementParseException if the given text can not be parsed.
+     * @since  1.4
+     */
+    @Override
+    public Quantity<?> parse(final CharSequence source, final ParsePosition 
pos) throws MeasurementParseException {
+        final int start = pos.getIndex();
+        final int shift;
+        final String text;
+        if (start == 0 || source instanceof String) {
+            shift = 0;
+            text  = source.toString();
+        } else {
+            shift = start;
+            text  = source.subSequence(start, source.length()).toString();
+            pos.setIndex(0);
+        }
+        try {
+            final Number value = numberFormat.parse(text, pos);
+            if (value != null) {
+                final Unit<?> unit = unitFormat.parse(text, pos);
+                if (unit != null) {
+                    return Quantities.create(value.doubleValue(), unit);
+                }
+            }
+        } finally {
+            if (shift != 0) {
+                pos.setIndex(pos.getIndex() + shift);
+                final int i = pos.getErrorIndex();
+                if (i >= 0) {
+                    pos.setErrorIndex(i + shift);
+                }
+            }
+        }
+        throw new 
MeasurementParseException(Errors.format(Errors.Keys.CanNotParse_1, source), 
source, pos.getErrorIndex());
+    }
+
     /**
      * Parses text from a string to produce a quantity, or returns {@code 
null} if the parsing failed.
      *
@@ -125,7 +227,7 @@ public class QuantityFormat extends Format {
                 if (unit != null) {
                     return Quantities.create(value.doubleValue(), unit);
                 }
-            } catch (ParserException e) {
+            } catch (MeasurementParseException e) {
                 Logging.ignorableException(getLogger(Loggers.MEASURE), 
QuantityFormat.class, "parseObject", e);
             }
             pos.setIndex(start);        // By `Format.parseObject(…)` method 
contract.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
index d379279c60..8824027bb6 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
@@ -20,9 +20,14 @@ import java.lang.reflect.Proxy;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 import javax.measure.UnitConverter;
+import javax.measure.UnconvertibleException;
+import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.StringBuilders;
 import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.logging.Logging;
+
+import static java.util.logging.Logger.getLogger;
 
 
 /**
@@ -33,7 +38,7 @@ import org.apache.sis.internal.util.Numerics;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.2
+ * @version 1.4
  *
  * @param <Q>  the type of quantity implemented by this scalar.
  *
@@ -46,6 +51,11 @@ class Scalar<Q extends Quantity<Q>> extends Number 
implements Quantity<Q>, Compa
      */
     private static final long serialVersionUID = -381805117700594712L;
 
+    /**
+     * The scale of this quantity. Currently only absolute scale is supported.
+     */
+    static final Scale SCALE = Scale.ABSOLUTE;
+
     /**
      * The numerical value of this quantity.
      */
@@ -113,6 +123,16 @@ class Scalar<Q extends Quantity<Q>> extends Number 
implements Quantity<Q>, Compa
         return this;
     }
 
+    /**
+     * Returns the scale of this quantity, which can be absolute or relative.
+     *
+     * @return whether this quantity uses absolute or relative scale.
+     */
+    @Override
+    public final Scale getScale() {
+        return SCALE;
+    }
+
     /**
      * Returns the unit of measurement specified at construction time.
      * The method shall not return {@code null}.
@@ -292,6 +312,14 @@ class Scalar<Q extends Quantity<Q>> extends Number 
implements Quantity<Q>, Compa
         return of(1 / value, unit.inverse());
     }
 
+    /**
+     * Returns a quantity whose value is {@code −getValue()}.
+     */
+    @Override
+    public final Quantity<Q> negate() {
+        return of(-value);
+    }
+
     /**
      * Ensures that this quantity is of the given type.
      */
@@ -300,6 +328,29 @@ class Scalar<Q extends Quantity<Q>> extends Number 
implements Quantity<Q>, Compa
         return type.cast(this);
     }
 
+    /**
+     * Compares this quantity with the given quantity, doing the conversion of 
unit if necessary.
+     *
+     * @param  that  the quantity to be compared with this instance.
+     * @return {@code true} if the two quantities are equivalent.
+     */
+    @Override
+    public final boolean isEquivalentTo(final Quantity<Q> that) {
+        final Unit<Q> otherUnit = that.getUnit();
+        try {
+            final Number r = 
otherUnit.getConverterTo(unit).convert(that.getValue());
+            if (r instanceof Float) {
+                return Math.abs(value - r.doubleValue()) < 
Math.ulp(r.floatValue());
+            } else {
+                return value == r.doubleValue();
+            }
+        } catch (UnconvertibleException e) {
+            Logging.ignorableException(getLogger(Loggers.MEASURE), 
Scalar.class, "isEquivalentTo", e);
+            // Non-convertible quantities are not equivalent.
+        }
+        return false;
+    }
+
     /**
      * Returns {@code true} if the given object is another {@code Scalar} with 
the same value and same unit
      * of measurement.
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 7538f52752..7d0dd9d534 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
@@ -43,7 +43,7 @@ import org.apache.sis.math.Fraction;
  * without scale factor or offset.
  *
  * @author  Martin Desruisseaux (MPO, Geomatys)
- * @version 1.1
+ * @version 1.4
  *
  * @param <Q>  the kind of quantity to be measured using this units.
  *
@@ -634,4 +634,20 @@ final class SystemUnit<Q extends Quantity<Q>> extends 
AbstractUnit<Q> implements
             return new Scalar<>(v, unit);
         }
     }
+
+    /**
+     * Creates a quantity for the given number stated in the specified unit 
and scale.
+     *
+     * @param  value  the numeric value stated in the specified unit.
+     * @param  unit   the unit of the value.
+     * @param  scale  the {@code ABSOLUTE} / {@code RELATIVE} scale of the 
quantity to create.
+     * @return the requested quantity.
+     */
+    @Override
+    public Quantity<Q> create(final Number value, final Unit<Q> unit, final 
Quantity.Scale scale) {
+        if (Objects.requireNonNull(scale) != Scalar.SCALE) {
+            throw new UnsupportedOperationException("Relative scale is not yet 
supported.");
+        }
+        return create(value, unit);
+    }
 }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
index 8c7a70f071..c412f7b2e5 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
@@ -32,7 +32,7 @@ import java.io.IOException;
 import java.io.UncheckedIOException;
 import javax.measure.Dimension;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.DefinitionURI;
@@ -1062,19 +1062,19 @@ appPow: if (unit == null) {
      *
      * @param  symbols  the unit symbols or URI to parse.
      * @return the unit parsed from the specified symbols.
-     * @throws ParserException if a problem occurred while parsing the given 
symbols.
+     * @throws MeasurementParseException if a problem occurred while parsing 
the given symbols.
      *
      * @see Units#valueOf(String)
      */
     @Override
-    public Unit<?> parse(final CharSequence symbols) throws ParserException {
+    public Unit<?> parse(final CharSequence symbols) throws 
MeasurementParseException {
         final Position position = new Position();
         Unit<?> unit = parse(symbols, position);
         final int length = symbols.length();
         int unrecognized;
         while ((unrecognized = CharSequences.skipLeadingWhitespaces(symbols, 
position.getIndex(), length)) < length) {
             if (position.finished || 
!Character.isLetter(Character.codePointAt(symbols, unrecognized))) {
-                throw new 
ParserException(Errors.format(Errors.Keys.UnexpectedCharactersAfter_2,
+                throw new 
MeasurementParseException(Errors.format(Errors.Keys.UnexpectedCharactersAfter_2,
                         CharSequences.trimWhitespaces(symbols, 0, 
unrecognized),
                         CharSequences.trimWhitespaces(symbols, unrecognized, 
length)),
                         symbols, unrecognized);
@@ -1096,16 +1096,16 @@ appPow: if (unit == null) {
      * Exponent after symbol can be decimal digits as in “m2” or a superscript 
as in “m²”.</p>
      *
      * <p>Note that contrarily to {@link #parseObject(String, ParsePosition)}, 
this method never return {@code null}.
-     * If an error occurs at parsing time, an unchecked {@link 
ParserException} is thrown.</p>
+     * If an error occurs at parsing time, an unchecked {@link 
MeasurementParseException} is thrown.</p>
      *
      * @param  symbols  the unit symbols to parse.
      * @param  position on input, index of the first character to parse.
      *                  On output, index after the last parsed character.
      * @return the unit parsed from the specified symbols.
-     * @throws ParserException if a problem occurred while parsing the given 
symbols.
+     * @throws MeasurementParseException if a problem occurred while parsing 
the given symbols.
      */
     @SuppressWarnings({"null", "fallthrough"})
-    public Unit<?> parse(CharSequence symbols, final ParsePosition position) 
throws ParserException {
+    public Unit<?> parse(CharSequence symbols, final ParsePosition position) 
throws MeasurementParseException {
         ArgumentChecks.ensureNonNull("symbols",  symbols);
         ArgumentChecks.ensureNonNull("position", position);
         /*
@@ -1129,7 +1129,8 @@ appPow: if (unit == null) {
                 } catch (NumberFormatException e) {
                     failure = e;
                 }
-                throw (ParserException) new 
ParserException(Errors.format(Errors.Keys.UnknownUnit_1,
+                throw (MeasurementParseException) new 
MeasurementParseException(
+                        Errors.format(Errors.Keys.UnknownUnit_1,
                         Constants.EPSG + Constants.DEFAULT_SEPARATOR + code), 
symbols,
                         start + Math.max(0, 
symbols.toString().lastIndexOf(code))).initCause(failure);
             }
@@ -1228,8 +1229,8 @@ scan:   for (int n; i < end; i += n) {
                     final Unit<?> term = parse(symbols, sub);
                     i = CharSequences.skipLeadingWhitespaces(symbols, 
sub.getIndex(), end);
                     if (i >= end || Character.codePointAt(symbols, i) != 
Style.CLOSE) {
-                        throw new 
ParserException(Errors.format(Errors.Keys.NonEquilibratedParenthesis_2,
-                               symbols.subSequence(start, i), Style.CLOSE), 
symbols, start);
+                        throw new 
MeasurementParseException(Errors.format(Errors.Keys.NonEquilibratedParenthesis_2,
+                                    symbols.subSequence(start, i), 
Style.CLOSE), symbols, start);
                     }
                     unit = operation.apply(unit, term, pos);
                     operation.code = Operation.IMPLICIT;    // Default 
operation if there is no × or / symbol after parenthesis.
@@ -1374,7 +1375,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
                             }
                         }
                     }
-                    throw new 
ParserException(Errors.format(Errors.Keys.NotAnInteger_1, term), symbols, 
position);
+                    throw new 
MeasurementParseException(Errors.format(Errors.Keys.NotAnInteger_1, term), 
symbols, position);
                 }
                 default: throw new AssertionError(code);
             }
@@ -1407,11 +1408,11 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
      * @param  upper      index after the last character to parse in the 
{@code symbols} string.
      * @param  operation  the operation to be applied (e.g. the term to be 
parsed is a multiplier or divisor of another unit).
      * @return the parsed unit symbol (never {@code null}).
-     * @throws ParserException if a problem occurred while parsing the given 
symbols.
+     * @throws MeasurementParseException if a problem occurred while parsing 
the given symbols.
      */
     @SuppressWarnings("fallthrough")
     private Unit<?> parseTerm(final CharSequence symbols, final int lower, 
final int upper, final Operation operation)
-            throws ParserException
+            throws MeasurementParseException
     {
         final String uom = CharSequences.trimWhitespaces(symbols, lower, 
upper).toString();
         /*
@@ -1453,7 +1454,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
                             }
                             multiplier = parseMultiplicationFactor(uom);
                         } catch (NumberFormatException e) {
-                            throw (ParserException) new 
ParserException(Errors.format(
+                            throw (MeasurementParseException) new 
MeasurementParseException(Errors.format(
                                     Errors.Keys.UnknownUnit_1, uom), symbols, 
lower).initCause(e);
                         }
                         if (operation.code == Operation.IMPLICIT) {
@@ -1489,7 +1490,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
                                     power = new Fraction(uom.substring(i));
                                 } catch (NumberFormatException e) {
                                     // Should never happen unless the number 
is larger than `int` capacity.
-                                    throw (ParserException) new 
ParserException(Errors.format(
+                                    throw (MeasurementParseException) new 
MeasurementParseException(Errors.format(
                                             Errors.Keys.UnknownUnit_1, uom), 
symbols, lower+i).initCause(e);
                                 }
                                 break;
@@ -1543,7 +1544,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
                     if (CharSequences.regionMatches(symbols, lower, UNITY, 
true)) {
                         return Units.UNITY;
                     }
-                    throw new 
ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, lower);
+                    throw new 
MeasurementParseException(Errors.format(Errors.Keys.UnknownUnit_1, uom), 
symbols, lower);
                 }
             }
         }
@@ -1580,8 +1581,9 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
     }
 
     /**
-     * Parses text from a string to produce a unit. The default implementation 
delegates to {@link #parse(CharSequence)}
-     * and wraps the {@link ParserException} into a {@link ParseException} for 
compatibility with {@code java.text} API.
+     * Parses text from a string to produce a unit. The default implementation 
delegates
+     * to {@link #parse(CharSequence)} and wraps the {@link 
MeasurementParseException}
+     * into a {@link ParseException} for compatibility with {@code java.text} 
API.
      *
      * @param  source  the text, part of which should be parsed.
      * @return a unit parsed from the string.
@@ -1591,7 +1593,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
     public Object parseObject(final String source) throws ParseException {
         try {
             return parse(source);
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             throw (ParseException) new ParseException(e.getLocalizedMessage(), 
e.getPosition()).initCause(e);
         }
     }
@@ -1599,7 +1601,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
     /**
      * Parses text from a string to produce a unit, or returns {@code null} if 
the parsing failed.
      * The default implementation delegates to {@link #parse(CharSequence, 
ParsePosition)} and catches
-     * the {@link ParserException}.
+     * the {@link MeasurementParseException}.
      *
      * @param  source  the text, part of which should be parsed.
      * @param  pos     index and error index information as described above.
@@ -1609,7 +1611,7 @@ search:     while ((i = 
CharSequences.skipTrailingWhitespaces(symbols, start, i)
     public Object parseObject(final String source, final ParsePosition pos) {
         try {
             return parse(source, pos);
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             pos.setErrorIndex(e.getPosition());
             return null;
         }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java
index d80df4a229..62d2a342bb 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java
@@ -26,9 +26,14 @@ import javax.measure.Unit;
 import javax.measure.Quantity;
 import javax.measure.Dimension;
 import javax.measure.spi.SystemOfUnits;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.math.Fraction;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.internal.system.Loggers;
+
+import static java.util.logging.Logger.getLogger;
 
 
 /**
@@ -37,7 +42,7 @@ import org.apache.sis.util.collection.WeakValueHashMap;
  * rather uses the static methods directly since we define all units in terms 
of SI.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   0.8
  * @module
  */
@@ -245,6 +250,24 @@ final class UnitRegistry implements SystemOfUnits, 
Serializable {
         return Units.get(type);
     }
 
+    /**
+     * Returns a unit with the given string representation,
+     * or {@code null} if none is found in this unit system.
+     *
+     * @param  symbols  the string representation of a unit.
+     * @return the unit with the given string representation,
+     *         or {@code null} if the give symbols can not be parsed.
+     */
+    @Override
+    public Unit<?> getUnit(final String symbols) {
+        try {
+            return Units.valueOf(symbols);
+        } catch (MeasurementParseException e) {
+            Logging.ignorableException(getLogger(Loggers.MEASURE), 
UnitRegistry.class, "getUnit", e);
+            return null;
+        }
+    }
+
     /**
      * Returns a read only view over the units explicitly defined by this 
system.
      * This include the base and derived units which are assigned a special 
name and symbol.
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
index c21f7131d5..86a65df55a 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
@@ -20,14 +20,16 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
+import java.text.NumberFormat;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 import javax.measure.format.UnitFormat;
+import javax.measure.format.QuantityFormat;
 import javax.measure.spi.QuantityFactory;
 import javax.measure.spi.ServiceProvider;
 import javax.measure.spi.SystemOfUnits;
 import javax.measure.spi.SystemOfUnitsService;
-import javax.measure.spi.UnitFormatService;
+import javax.measure.spi.FormatService;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.util.logging.Logging;
@@ -42,15 +44,15 @@ import static java.util.logging.Logger.getLogger;
  * The central point from which all unit services (parsing, formatting, 
listing, <i>etc</i>) can be obtained.
  * Apache SIS does not use this class (SIS rather uses {@link Units} 
predefined constants and {@link UnitFormat}
  * directly since they are designed specifically for SIS needs).
- * This class is provided for allowing other applications to discover Apache 
SIS implementation of JSR-363
+ * This class is provided for allowing other applications to discover Apache 
SIS implementation of JSR-385
  * without direct dependency. A {@code UnitServices} instance can be obtained 
by call to {@link #current()}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   0.8
  * @module
  */
-public class UnitServices extends ServiceProvider implements 
SystemOfUnitsService, UnitFormatService {
+public class UnitServices extends ServiceProvider implements 
SystemOfUnitsService, FormatService {
     /**
      * All system of units known to this provider.
      * The last element in the array is the default system with all units 
known to SIS.
@@ -181,7 +183,7 @@ public class UnitServices extends ServiceProvider 
implements SystemOfUnitsServic
         try {
             style = org.apache.sis.measure.UnitFormat.Style.valueOf(name);
         } catch (IllegalArgumentException e) {
-            // JSR-363 specification mandate that we return null.
+            // JSR-385 specification mandate that we return null.
             Logging.recoverableException(getLogger(Loggers.MEASURE), 
UnitServices.class, "getUnitFormat", e);
             return null;
         }
@@ -190,14 +192,60 @@ public class UnitServices extends ServiceProvider 
implements SystemOfUnitsServic
         return f;
     }
 
+    /**
+     * Returns the unit format having the specified name or {@code null} if 
none.
+     * The variant is an optional argument for requesting e.g. ASCII-only 
format,
+     * or for choosing case-sensitive versus case-insensitive variants.
+     * In current implementation the variant argument is ignored.
+     *
+     * @param  name     the name of the desired format.
+     * @param  variant  indicates a variation of a unit format.
+     * @return the corresponding unit format, or {@code null} if none.
+     * @since  1.4
+     */
+    @Override
+    public UnitFormat getUnitFormat(final String name, final String variant) {
+        return getUnitFormat(name);
+    }
+
+    /**
+     * Returns a quantity format for the default locale.
+     *
+     * @return a {@link tech.uom.seshat.QuantityFormat} instance for 
quantities.
+     * @since  1.4
+     */
+    @Override
+    public QuantityFormat getQuantityFormat() {
+        return new 
org.apache.sis.measure.QuantityFormat(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Returns the quantity format having the specified name or {@code null} 
if none.
+     * The names accepted by this method are those documented in {@link 
#getUnitFormat(String)}.
+     *
+     * @param  name  the name of the format.
+     * @return the corresponding quantity format, or {@code null} if none.
+     * @since  1.4
+     */
+    @Override
+    public QuantityFormat getQuantityFormat(final String name) {
+        final UnitFormat unitFormat = getUnitFormat(name);
+        if (unitFormat instanceof org.apache.sis.measure.UnitFormat) {
+            return new 
org.apache.sis.measure.QuantityFormat(NumberFormat.getInstance(),
+                        (org.apache.sis.measure.UnitFormat) unitFormat);
+        }
+        return null;
+    }
+
     /**
      * Returns a list of available format names. The default implementation 
returns the names
      * of all values in the {@link org.apache.sis.measure.UnitFormat.Style} 
enumeration.
      *
+     * @param  type  the type of formats (for units or for quantities).
      * @return list of available formats.
      */
     @Override
-    public Set<String> getAvailableFormatNames() {
+    public Set<String> getAvailableFormatNames(final FormatType type) {
         final Set<String> names = new HashSet<>(4);
         for (final Enum<?> e : 
org.apache.sis.measure.UnitFormat.Style.values()) {
             names.add(e.name());
@@ -213,13 +261,13 @@ public class UnitServices extends ServiceProvider 
implements SystemOfUnitsServic
      * <ul>
      *   <li>{@link #getUnitFormat()}</li>
      *   <li>{@link #getUnitFormat(String)}</li>
-     *   <li>{@link #getAvailableFormatNames()}</li>
+     *   <li>{@link #getAvailableFormatNames(FormatType)}</li>
      * </ul>
      *
      * @return the service to obtain a {@link UnitFormat}, or {@code null} if 
none.
      */
     @Override
-    public UnitFormatService getUnitFormatService() {
+    public FormatService getFormatService() {
         return this;
     }
 
@@ -239,29 +287,14 @@ public class UnitServices extends ServiceProvider 
implements SystemOfUnitsServic
         QuantityFactory<Q> factory = Units.get(type);
         if (factory == null) {
             if (type != null) {
-                factory = new QuantityFactory<Q>() {
+                factory = new DefaultQuantityFactory<Q>() {
                     @Override
                     public Quantity<Q> create(final Number value, final 
Unit<Q> unit) {
                         return 
ScalarFallback.factory(AbstractConverter.doubleValue(value), unit, type);
                     }
-
-                    @Override
-                    public Unit<Q> getSystemUnit() {
-                        return null;
-                    }
                 };
             } else {
-                factory = new QuantityFactory<Q>() {
-                    @Override
-                    public Quantity<Q> create(final Number value, final 
Unit<Q> unit) {
-                        return new 
Scalar<>(AbstractConverter.doubleValue(value), unit);
-                    }
-
-                    @Override
-                    public Unit<Q> getSystemUnit() {
-                        return null;
-                    }
-                };
+                factory = new DefaultQuantityFactory<>();
             }
         }
         return factory;
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 9d4a217e28..8354f331cd 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
@@ -19,7 +19,7 @@ package org.apache.sis.measure;
 import javax.measure.Dimension;
 import javax.measure.Unit;
 import javax.measure.UnitConverter;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import javax.measure.Quantity;
 import javax.measure.quantity.*;
 import javax.measure.quantity.Angle;                // Because of name 
collision with Angle in this SIS package.
@@ -1665,7 +1665,7 @@ public final class Units extends Static {
                 return new Number[0];
             }
             if (converter.isLinear()) {
-                final double offset = converter.convert(0);  // Should be zero 
as per JSR-363 specification, but we are paranoiac.
+                final double offset = converter.convert(0);  // Should be zero 
as per JSR-385 specification, but we are paranoiac.
                 final double scale  = converter.convert(1) - offset;
                 final Number[] c = new Number[(scale != 1) ? 2 : (offset != 0) 
? 1 : 0];
                 switch (c.length) {
@@ -1713,11 +1713,11 @@ public final class Units extends Static {
      *
      * @param  uom  the symbol to parse, or {@code null}.
      * @return the parsed symbol, or {@code null} if {@code uom} was null.
-     * @throws ParserException if the given symbol cannot be parsed.
+     * @throws MeasurementParseException if the given symbol cannot be parsed.
      *
      * @see UnitFormat#parse(CharSequence)
      */
-    public static Unit<?> valueOf(String uom) throws ParserException {
+    public static Unit<?> valueOf(String uom) throws MeasurementParseException 
{
         return (uom != null) ? UnitFormat.INSTANCE.parse(uom) : null;
     }
 
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java
index b5db469858..662ee16193 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java
@@ -97,7 +97,7 @@
  *
  * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   0.3
  * @module
  */
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 1fa30b9ce0..f5a612f4c6 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
@@ -31,7 +31,7 @@ import static org.opengis.test.Assert.*;
  * Tests {@link Quantities}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.8
  * @module
  */
@@ -58,6 +58,7 @@ public final strictfp class QuantitiesTest extends TestCase {
         q = new Quantity<Length>() {
             @Override public Number           getValue()                       
  {return 8;}
             @Override public Unit<Length>     getUnit ()                       
  {return Units.CENTIMETRE;}
+            @Override public Scale            getScale()                       
  {return Scale.ABSOLUTE;}
             @Override public Quantity<Length> add     (Quantity<Length> 
ignored) {return null;}
             @Override public Quantity<Length> subtract(Quantity<Length> 
ignored) {return null;}
             @Override public Quantity<?>      multiply(Quantity<?>      
ignored) {return null;}
@@ -65,7 +66,9 @@ public final strictfp class QuantitiesTest extends TestCase {
             @Override public Quantity<Length> multiply(Number           
ignored) {return null;}
             @Override public Quantity<Length> divide  (Number           
ignored) {return null;}
             @Override public Quantity<?>      inverse ()                       
  {return null;}
+            @Override public Quantity<Length> negate  ()                       
  {return null;}
             @Override public Quantity<Length> to      (Unit<Length>     
ignored) {return null;}
+            @Override public boolean    isEquivalentTo(Quantity<Length> 
ignored) {return false;}
             @Override public <T extends Quantity<T>> Quantity<T> 
asType(Class<T> ignored) {return null;}
         };
         final Length c = Quantities.castOrCopy(q);
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/SystemUnitTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/SystemUnitTest.java
index ced8c18b29..ba5754cfb5 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/SystemUnitTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/SystemUnitTest.java
@@ -130,7 +130,7 @@ public final strictfp class SystemUnitTest extends TestCase 
{
      */
     @Test
     public void testGetBaseDimensions() {
-        assertNull("METRE",  Units.METRE .getBaseUnits());      // Null value 
as per JSR-363 specification.
+        assertNull("METRE",  Units.METRE .getBaseUnits());      // Null value 
as per JSR-385 specification.
         assertNull("SECOND", Units.SECOND.getBaseUnits());
         assertTrue("UNITY",  Units.UNITY .getBaseUnits().isEmpty());
 
@@ -199,7 +199,7 @@ public final strictfp class SystemUnitTest extends TestCase 
{
         assertTrue (Units.RADIAN.isCompatible(Units.RADIAN));
         assertFalse(Units.RADIAN.isCompatible(Units.METRE ));
         assertFalse(Units.METRE .isCompatible(Units.RADIAN));
-        assertTrue (Units.UNITY .isCompatible(Units.RADIAN));   // Really true 
(not false) as per JSR-363 specification.
+        assertTrue (Units.UNITY .isCompatible(Units.RADIAN));   // Really true 
(not false) as per JSR-385 specification.
         assertTrue (Units.RADIAN.isCompatible(Units.UNITY ));
     }
 
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitDimensionTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitDimensionTest.java
index b1f9588efc..b886b7bf73 100644
--- 
a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitDimensionTest.java
+++ 
b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitDimensionTest.java
@@ -140,7 +140,7 @@ public final strictfp class UnitDimensionTest extends 
TestCase {
      */
     @Test
     public void testGetBaseDimensions() {
-        assertNull("LENGTH",        LENGTH       .getBaseDimensions());     // 
Null value as per JSR-363 specification.
+        assertNull("LENGTH",        LENGTH       .getBaseDimensions());     // 
Null value as per JSR-385 specification.
         assertNull("TIME",          TIME         .getBaseDimensions());
         assertTrue("DIMENSIONLESS", 
DIMENSIONLESS.getBaseDimensions().isEmpty());
         assertMapEquals(Map.of(LENGTH, 3), VOLUME.getBaseDimensions());
@@ -165,7 +165,7 @@ public final strictfp class UnitDimensionTest extends 
TestCase {
         verifyEqualsAndHashCode("Derived dimensions", false, Units.NEWTON, 
Units.JOULE);
         verifyEqualsAndHashCode("Dimensionsless",     true,  Units.UNITY,  
Units.UNITY);
         verifyEqualsAndHashCode("Dimensionsless",     true,  Units.DEGREE, 
Units.DEGREE);
-        verifyEqualsAndHashCode("Dimensionsless",     true,  Units.UNITY,  
Units.DEGREE);    // Really true (not false) as per JSR-363 specification.
+        verifyEqualsAndHashCode("Dimensionsless",     true,  Units.UNITY,  
Units.DEGREE);    // Really true (not false) as per JSR-385 specification.
         verifyEqualsAndHashCode("Mixed types",        false, Units.METRE,  
Units.UNITY);
         verifyEqualsAndHashCode("Mixed types",        false, Units.METRE,  
Units.NEWTON);
     }
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
index ef17c2998a..d955a9be98 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
@@ -23,7 +23,7 @@ import java.text.ParsePosition;
 import java.lang.reflect.Field;
 import javax.measure.Unit;
 import javax.measure.quantity.Length;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Characters;
 import org.apache.sis.test.DependsOn;
@@ -193,7 +193,7 @@ public final strictfp class UnitFormatTest extends TestCase 
{
         try {
             f.parse("mFoo");
             fail("“mFoo” should not be assigned to unit anymore.");
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("mFoo"));
         }
@@ -393,7 +393,7 @@ public final strictfp class UnitFormatTest extends TestCase 
{
         try {
             f.parse("degree foo");
             fail("Should not accept unknown unit.");
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("degree"));
             assertTrue(message, message.contains("foo"));
@@ -402,7 +402,7 @@ public final strictfp class UnitFormatTest extends TestCase 
{
         try {
             f.parse("mètre cube");
             fail("Should not accept localized unit unless requested.");
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("mètre"));
             assertTrue(message, message.contains("cube"));
@@ -485,7 +485,7 @@ public final strictfp class UnitFormatTest extends TestCase 
{
         try {
             f.parse("ka");
             fail("Should not accept prefix in ConventionalUnit.");
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("ka"));
         }
@@ -519,7 +519,7 @@ public final strictfp class UnitFormatTest extends TestCase 
{
         try {
             f.parse("degree minute");
             fail("Should not accept unknown sentence even if each individual 
word is known.");
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("degree"));
             assertTrue(message, message.contains("minute"));
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java
index 3c1e667751..af79a1d2cc 100644
--- 
a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java
+++ 
b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java
@@ -17,10 +17,10 @@
 package org.apache.sis.measure;
 
 import java.util.Set;
-import java.util.List;
 import java.util.Locale;
 import javax.measure.Unit;
 import javax.measure.format.UnitFormat;
+import javax.measure.spi.FormatService;
 import javax.measure.spi.ServiceProvider;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -33,7 +33,7 @@ import static org.apache.sis.test.Assert.*;
  * Test {@link UnitServices}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.8
  * @module
  */
@@ -115,13 +115,14 @@ public final strictfp class UnitServicesTest extends 
TestCase {
     }
 
     /**
-     * Tests {@link UnitServices#getAvailableFormatNames()}.
+     * Tests {@link 
UnitServices#getAvailableFormatNames(UnitServices.FormatType)}.
      */
     @Test
     public void testGetAvailableFormatNames() {
         final ServiceProvider provider = ServiceProvider.current();
-        assertSetEquals(List.of("SYMBOL", "UCUM", "NAME"),
-                provider.getUnitFormatService().getAvailableFormatNames());
+        final FormatService service = provider.getFormatService();
+        final Set<String> formats = 
service.getAvailableFormatNames(FormatService.FormatType.UNIT_FORMAT);
+        assertSetEquals(Set.of("SYMBOL", "UCUM", "NAME"), formats);
     }
 
     /**
@@ -130,7 +131,7 @@ public final strictfp class UnitServicesTest extends 
TestCase {
     @Test
     public void testGetUnitFormat() {
         final ServiceProvider provider = ServiceProvider.current();
-        final UnitFormat f = 
provider.getUnitFormatService().getUnitFormat("name");
+        final UnitFormat f = provider.getFormatService().getUnitFormat("name");
         ((org.apache.sis.measure.UnitFormat) f).setLocale(Locale.US);
         assertEquals("CUBIC_METRE", "cubic meter", 
f.format(Units.CUBIC_METRE));
     }
diff --git a/ide-project/NetBeans/nbproject/project.properties 
b/ide-project/NetBeans/nbproject/project.properties
index e537f44c7a..7a129754dd 100644
--- a/ide-project/NetBeans/nbproject/project.properties
+++ b/ide-project/NetBeans/nbproject/project.properties
@@ -98,7 +98,7 @@ project.GeoAPI       = 
../../../../GeoAPI/master/ide-project/NetBeans
 # Those dependencies must exist in the local Maven repository.
 # Those numbers should match the ones declared in the pom.xml files.
 #
-jsr363.version       = 1.0
+jsr385.version       = 2.1.3
 jaxb.version         = 2.3.3
 jaxb.runtime         = 2.3.7
 istack.version       = 3.0.12
@@ -131,7 +131,7 @@ maven.repository   = ${user.home}/.m2/repository
 endorsed.classpath =
 javac.classpath=\
     ${project.GeoAPI}/dist/geoapi.jar:\
-    
${maven.repository}/javax/measure/unit-api/${jsr363.version}/unit-api-${jsr363.version}.jar:\
+    
${maven.repository}/javax/measure/unit-api/${jsr385.version}/unit-api-${jsr385.version}.jar:\
     
${maven.repository}/jakarta/xml/bind/jakarta.xml.bind-api/${jaxb.version}/jakarta.xml.bind-api-${jaxb.version}.jar:\
     
${maven.repository}/com/esri/geometry/esri-geometry-api/${esri.api.version}/esri-geometry-api-${esri.api.version}.jar:\
     
${maven.repository}/org/locationtech/jts/jts-core/${jts.version}/jts-core-${jts.version}.jar:\
diff --git 
a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
 
b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
index 2d31d1553c..5a6e3a2920 100644
--- 
a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
+++ 
b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
 import java.util.function.Function;
 import java.awt.Color;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
@@ -568,10 +568,10 @@ public final class GCOM_C extends Convention {
      *
      * @param  data  the variable for which to get the unit of measurement.
      * @return the unit of measurement, or {@code null} if none or unknown.
-     * @throws ParserException if the unit symbol cannot be parsed.
+     * @throws MeasurementParseException if the unit symbol cannot be parsed.
      */
     @Override
-    public Unit<?> getUnitFallback(final Variable data) throws ParserException 
{
+    public Unit<?> getUnitFallback(final Variable data) throws 
MeasurementParseException {
         if ("Image_data".equals(data.getGroupName())) {
             final String symbol = data.getAttributeAsString("Unit");
             if (symbol != null && !symbol.equalsIgnoreCase("NA")) {
diff --git 
a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java
 
b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java
index 90e0cd85b6..a77f0f9e76 100644
--- 
a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java
+++ 
b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java
@@ -20,7 +20,7 @@ import java.util.Set;
 import java.util.Map;
 import java.util.regex.Pattern;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.apache.sis.measure.Units;
 import org.apache.sis.storage.netcdf.AttributeNames;
 import org.apache.sis.internal.netcdf.Convention;
@@ -262,10 +262,10 @@ public final class GCOM_W extends Convention {
      *
      * @param  data  the variable for which to get the unit of measurement.
      * @return the unit of measurement, or {@code null} if none or unknown.
-     * @throws ParserException if the unit symbol cannot be parsed.
+     * @throws MeasurementParseException if the unit symbol cannot be parsed.
      */
     @Override
-    public Unit<?> getUnitFallback(final Variable data) throws ParserException 
{
+    public Unit<?> getUnitFallback(final Variable data) throws 
MeasurementParseException {
         final String symbol = data.getAttributeAsString("UNIT");
         if (symbol == null) {
             return super.getUnitFallback(data);
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
index 4ebf91fd61..f8c2581ca7 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
@@ -25,7 +25,7 @@ import java.util.Locale;
 import java.util.function.Function;
 import java.awt.Color;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.operation.MathTransform;
@@ -768,9 +768,9 @@ public class Convention {
      *
      * @param  data  the variable for which to get the unit of measurement.
      * @return the unit of measurement, or {@code null} if none or unknown.
-     * @throws ParserException if the unit symbol cannot be parsed.
+     * @throws MeasurementParseException if the unit symbol cannot be parsed.
      */
-    public Unit<?> getUnitFallback(final Variable data) throws ParserException 
{
+    public Unit<?> getUnitFallback(final Variable data) throws 
MeasurementParseException {
         return null;
     }
 
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index e6806fd169..fb0254c035 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
 import java.io.IOException;
 import java.time.Instant;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.referencing.operation.Matrix;
 import org.apache.sis.referencing.operation.transform.TransferFunction;
 import org.apache.sis.storage.DataStoreException;
@@ -401,7 +401,7 @@ public abstract class Variable extends Node {
             }
             if (unit == null) try {
                 unit = decoder.convention().getUnitFallback(this);
-            } catch (ParserException ex) {
+            } catch (MeasurementParseException ex) {
                 if (error == null) error = ex;
                 else error.addSuppressed(ex);
                 if (symbols == null) {
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
index 47098327d6..17c125a46b 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
@@ -39,7 +39,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.channels.ReadableByteChannel;
 import javax.measure.UnitConverter;
 import javax.measure.IncommensurableException;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import org.opengis.parameter.InvalidParameterCardinalityException;
 import org.apache.sis.internal.netcdf.DataType;
 import org.apache.sis.internal.netcdf.Decoder;
@@ -899,7 +899,7 @@ public final class ChannelDecoder extends Decoder {
                     dates[i] = new Date(epoch + 
Math.round(converter.convert(value.doubleValue())));
                 }
             }
-        } catch (IncommensurableException | ParserException | 
DateTimeException | ArithmeticException e) {
+        } catch (IncommensurableException | MeasurementParseException | 
DateTimeException | ArithmeticException e) {
             listeners.warning(e);
         }
         return dates;
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
index cf36e097d4..997e0aa9ff 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
@@ -28,7 +28,7 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.time.format.DateTimeParseException;
 import javax.measure.Unit;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 import ucar.nc2.constants.CF;
 import ucar.nc2.constants.CDM;
 import ucar.nc2.constants._Coordinate;
@@ -416,7 +416,7 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
      * Parses the given unit symbol and set the {@link #epoch} if the parsed 
unit is a temporal unit.
      * This method is called by {@link #getUnit()}.
      *
-     * @throws ParserException if the given symbol cannot be parsed.
+     * @throws MeasurementParseException if the given symbol cannot be parsed.
      */
     @Override
     protected Unit<?> parseUnit(String symbols) {
@@ -443,7 +443,7 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
         final Unit<?> unit;
         try {
             unit = Units.valueOf(symbols);
-        } catch (ParserException e) {
+        } catch (MeasurementParseException e) {
             if (dateError != null) {
                 e.addSuppressed(dateError);
             }
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index 4ee557155e..839493059d 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -31,7 +31,7 @@ import java.io.IOException;
 import javax.measure.Unit;
 import javax.measure.UnitConverter;
 import javax.measure.IncommensurableException;
-import javax.measure.format.ParserException;
+import javax.measure.format.MeasurementParseException;
 
 import org.opengis.util.CodeList;
 import org.opengis.util.NameFactory;
@@ -725,7 +725,7 @@ split:  while ((start = 
CharSequences.skipLeadingWhitespaces(value, start, lengt
                     final String symbol = res.substring(s+1).trim();
                     if (!symbol.isEmpty()) try {
                         units = Units.valueOf(symbol);
-                    } catch (ParserException e) {
+                    } catch (MeasurementParseException e) {
                         warning(Errors.Keys.CanNotAssignUnitToDimension_2, 
name, units, e);
                     }
                 }
@@ -816,7 +816,7 @@ split:  while ((start = 
CharSequences.skipLeadingWhitespaces(value, start, lengt
                     final UnitConverter c = 
Units.valueOf(symbol).getConverterToAny(targetUnit);
                     min = c.convert(min);
                     max = c.convert(max);
-                } catch (ParserException | IncommensurableException e) {
+                } catch (MeasurementParseException | IncommensurableException 
e) {
                     warning(e);
                 }
                 boolean reverse = false;

Reply via email to