sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1685763 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/io/wkt/ sis-metadata/src/test/java/org/apache/sis/io/wkt/ sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ sis-referencing/src/test/java/org/apac...
Date Tue, 16 Jun 2015 11:28:29 GMT
Author: desruisseaux
Date: Tue Jun 16 11:28:28 2015
New Revision: 1685763

URL: http://svn.apache.org/r1685763
Log:
WKT 2: support parsing of LengthUnit, AngleUnit, etc. in AXIS[...] components.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
    sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -27,8 +27,11 @@ import java.text.DecimalFormat;
 import java.text.ParsePosition;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import javax.measure.unit.Unit;
+import javax.measure.unit.UnitFormat;
 import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
+import org.apache.sis.measure.Units;
 import org.apache.sis.util.Workaround;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -88,6 +91,11 @@ abstract class AbstractParser implements
     private DateFormat dateFormat;
 
     /**
+     * The object to use for parsing unit symbols, created when first needed.
+     */
+    private UnitFormat unitFormat;
+
+    /**
      * Keyword of unknown elements. The ISO 19162 specification requires that we ignore unknown elements,
      * but we will nevertheless report them as warnings.
      * The meaning of this map is:
@@ -113,9 +121,12 @@ abstract class AbstractParser implements
      * @param symbols       The set of symbols to use.
      * @param numberFormat  The number format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param dateFormat    The date format provided by {@link WKTFormat}, or {@code null} for a default format.
+     * @param unitFormat    The unit format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param errorLocale   The locale for error messages (not for parsing), or {@code null} for the system default.
      */
-    AbstractParser(final Symbols symbols, NumberFormat numberFormat, final DateFormat dateFormat, final Locale errorLocale) {
+    AbstractParser(final Symbols symbols, NumberFormat numberFormat, final DateFormat dateFormat,
+            final UnitFormat unitFormat, final Locale errorLocale)
+    {
         ensureNonNull("symbols", symbols);
         if (numberFormat == null) {
             numberFormat = symbols.createNumberFormat();
@@ -123,6 +134,7 @@ abstract class AbstractParser implements
         this.symbols      = symbols;
         this.numberFormat = numberFormat;
         this.dateFormat   = dateFormat;
+        this.unitFormat   = unitFormat;
         this.errorLocale  = errorLocale;
         if (SCIENTIFIC_NOTATION && numberFormat instanceof DecimalFormat) {
             final DecimalFormat decimalFormat = (DecimalFormat) numberFormat;
@@ -227,6 +239,31 @@ abstract class AbstractParser implements
     }
 
     /**
+     * Parses the given unit symbol.
+     */
+    final Unit<?> parseUnit(final String text) throws ParseException {
+        if (unitFormat == null) {
+            if (symbols.getLocale() == Locale.ROOT) {
+                return Units.valueOf(text); // Most common case, avoid the convolved code below.
+            }
+            unitFormat = UnitFormat.getInstance(symbols.getLocale());
+        }
+        /*
+         * This convolved code tries to workaround JSR-275 limitations.
+         */
+        try {
+            return (Unit<?>) unitFormat.parseObject(text);
+        } catch (ParseException e) {
+            try {
+                return Units.valueOf(text);
+            } catch (IllegalArgumentException e2) {
+                e.addSuppressed(e2);
+                throw e;
+            }
+        }
+    }
+
+    /**
      * Reports a non-fatal warning that occurred while parsing a WKT.
      *
      * @param parent  The parent element.

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -77,6 +77,14 @@ final class Element {
     final int offset;
 
     /**
+     * Index of the keyword in the array given to the {@link #pullElement(String...)}
+     * or {@link #pullOptionalElement(String...)} method.
+     *
+     * @see #getKeywordIndex()
+     */
+    private byte keywordIndex;
+
+    /**
      * Keyword of this entity. For example: {@code "PrimeMeridian"}.
      */
     public final String keyword;
@@ -344,11 +352,11 @@ final class Element {
     }
 
     /**
-     * Returns an exception saying that a component is missing.
+     * Returns an exception saying that a sub-element is missing.
      *
-     * @param key The name of the missing component.
+     * @param key The name of the missing sub-element.
      */
-    private ParseException missingParameter(final String key) {
+    final ParseException missingComponent(final String key) {
         int error = offset;
         if (keyword != null) {
             error += keyword.length();
@@ -382,7 +390,7 @@ final class Element {
                 return (Date) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -401,7 +409,7 @@ final class Element {
                 return ((Number) object).doubleValue();
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -425,7 +433,7 @@ final class Element {
                 return number.intValue();
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -444,7 +452,7 @@ final class Element {
                 return (Boolean) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -463,7 +471,7 @@ final class Element {
                 return (String) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -482,42 +490,46 @@ final class Element {
                 return object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
      * Removes the next {@link Element} from the list and returns it.
+     * If the parameter is missing, then the first element in the given {@code keys} array
+     * will be taken as the name of the missing element to report in the exception message.
      *
-     * @param  key The element name (e.g. {@code "PrimeMeridian"}).
+     * @param  keys The element names (e.g. {@code "PrimeMeridian"}).
      * @return The next {@link Element} on the list.
      * @throws ParseException if no more element is available.
      */
-    public Element pullElement(final String key) throws ParseException {
-        final Element element = pullOptionalElement(key, null);
+    public Element pullElement(final String... keys) throws ParseException {
+        final Element element = pullOptionalElement(keys);
         if (element != null) {
             return element;
         }
-        throw missingParameter(key);
+        throw missingComponent(keys[0]);
     }
 
     /**
      * Removes the next {@link Element} from the list and returns it.
      *
-     * @param  key    The element name (e.g. {@code "PrimeMeridian"}).
-     * @param  aktKey An alternative key, or {@code null} if none.
+     * @param  keys The element names (e.g. {@code "PrimeMeridian"}).
      * @return The next {@link Element} on the list, or {@code null} if no more element is available.
      */
-    public Element pullOptionalElement(final String key, final String altKey) {
+    public Element pullOptionalElement(final String... keys) {
         final Iterator<Object> iterator = list.iterator();
         while (iterator.hasNext()) {
             final Object object = iterator.next();
             if (object instanceof Element) {
                 final Element element = (Element) object;
-                if (element.list != null && (key.equalsIgnoreCase(element.keyword) ||
-                       (altKey != null && altKey.equalsIgnoreCase(element.keyword))))
-                {
-                    iterator.remove();
-                    return element;
+                if (element.list != null) {
+                    for (int i=0; i<keys.length; i++) {
+                        if (element.keyword.equalsIgnoreCase(keys[i])) {
+                            keywordIndex = (byte) i;
+                            iterator.remove();
+                            return element;
+                        }
+                    }
                 }
             }
         }
@@ -544,7 +556,7 @@ final class Element {
                 }
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -567,6 +579,14 @@ final class Element {
     }
 
     /**
+     * Returns the index of the keyword in the array given to the {@link #pullElement(String...)}
+     * or {@link #pullOptionalElement(String...)} method.
+     */
+    final int getKeywordIndex() {
+        return keywordIndex;
+    }
+
+    /**
      * Closes this element. This method verifies that there is no unprocessed value (dates,
      * numbers, booleans or strings), but ignores inner elements as required by ISO 19162.
      *

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -27,6 +27,7 @@ import java.text.NumberFormat;
 import java.text.ParsePosition;
 import java.text.ParseException;
 import javax.measure.unit.Unit;
+import javax.measure.unit.UnitFormat;
 import javax.measure.unit.SI;
 import javax.measure.unit.NonSI;
 import javax.measure.quantity.Angle;
@@ -77,21 +78,6 @@ import static java.util.Collections.sing
  * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform Math Transform} objects.
  * Note that math transforms are part of the WKT 1 {@code "FITTED_CS"} element.
  *
- * <div class="section">Default axis names</div>
- * The WKT 1 specification defined axis names different than the ISO 19111 ones.
- * This parser replaces the WKT 1 names by the ISO names and abbreviations when possible.
- *
- * <table class="sis">
- *   <tr><th>CRS type</th>   <th>WKT1 names</th> <th>ISO abbreviations</th></tr>
- *   <tr><td>Geographic</td> <td>Lon, Lat</td>   <td>λ, φ</td></tr>
- *   <tr><td>Vertical</td>   <td>H</td>          <td>h</td></tr>
- *   <tr><td>Projected</td>  <td>X, Y</td>       <td>x, y</td></tr>
- *   <tr><td>Geocentric</td> <td>X, Y, Z</td>    <td>X, Y, Z</td></tr>
- * </table>
- *
- * The default behavior is to use the ISO identifiers.
- * This behavior can be changed by setting the parsing conventions to {@link Convention#WKT1}.
- *
  * @author  Rémi Eve (IRD)
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.6
@@ -100,6 +86,22 @@ import static java.util.Collections.sing
  */
 final class GeodeticObjectParser extends MathTransformParser {
     /**
+     * The keywords of unit elements. Most frequently used keywords should be first.
+     */
+    private static final String[] UNIT_KEYWORDS = {
+        WKTKeywords.Unit,   // Ignored since it does not allow us to know the quantity dimension.
+        WKTKeywords.LengthUnit, WKTKeywords.AngleUnit, WKTKeywords.ScaleUnit, WKTKeywords.TimeUnit
+    };
+
+    /**
+     * The base unit associated to the {@link #UNIT_KEYWORDS}, ignoring {@link WKTKeywords#Unit}.
+     * For each {@code UNIT_KEYWORDS[i]} element, the associated base unit is {@code BASE_UNIT[i]}.
+     */
+    private static final Unit<?>[] BASE_UNITS = {
+        SI.METRE, SI.RADIAN, Unit.ONE, SI.SECOND
+    };
+
+    /**
      * The names of the 7 parameters in a {@code TOWGS84[…]} element.
      * Those names are derived from the <cite>Well Known Text</cite> (WKT) version 1 specification.
      * They are not the same than the {@link org.apache.sis.referencing.datum.BursaWolfParameters}
@@ -140,6 +142,9 @@ final class GeodeticObjectParser extends
      *   <li>{@link Convention#WKT1_COMMON_UNITS} means that {@code PRIMEM} and {@code PARAMETER} angular units
      *       need to be forced to {@code NonSI.DEGREE_ANGLE} instead than inferred from the context.
      *       Note that this rule does not apply to {@code AXIS} elements.</li>
+     *
+     *   <li>{@link Convention#WKT1_IGNORE_AXES} means that axes should be parsed only for verifying the syntax,
+     *       but otherwise parsing should behave as if axes were not declared.</li>
      * </ul>
      */
     private final Convention convention;
@@ -163,7 +168,7 @@ final class GeodeticObjectParser extends
     /**
      * A chained list of temporary information needed for completing the construction of {@link DefaultVerticalExtent}
      * instances. In particular, stores the unit of measurement until the {@link VerticalCRS} instance to associate to
-     * the extents is known.
+     * the extents become known.
      */
     private transient VerticalInfo verticalElements;
 
@@ -171,7 +176,7 @@ final class GeodeticObjectParser extends
      * Creates a parser using the default set of symbols and factories.
      */
     public GeodeticObjectParser() {
-        this(Symbols.getDefault(), null, null, Convention.DEFAULT, null, null);
+        this(Symbols.getDefault(), null, null, null, Convention.DEFAULT, null, null);
     }
 
     /**
@@ -191,7 +196,7 @@ final class GeodeticObjectParser extends
     public GeodeticObjectParser(final Map<String,?> defaultProperties,
             final ObjectFactory factories, final MathTransformFactory mtFactory)
     {
-        super(Symbols.getDefault(), null, null, mtFactory, (Locale) defaultProperties.get(Errors.LOCALE_KEY));
+        super(Symbols.getDefault(), null, null, null, mtFactory, (Locale) defaultProperties.get(Errors.LOCALE_KEY));
         crsFactory    = (CRSFactory)   factories;
         csFactory     = (CSFactory)    factories;
         datumFactory  = (DatumFactory) factories;
@@ -207,14 +212,16 @@ final class GeodeticObjectParser extends
      * @param symbols       The set of symbols to use.
      * @param numberFormat  The number format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param dateFormat    The date format provided by {@link WKTFormat}, or {@code null} for a default format.
+     * @param unitFormat    The unit format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param convention    The WKT convention to use.
      * @param errorLocale   The locale for error messages (not for parsing), or {@code null} for the system default.
      * @param factories     On input, the factories to use. On output, the factories used. Can be null.
      */
     GeodeticObjectParser(final Symbols symbols, final NumberFormat numberFormat, final DateFormat dateFormat,
-            final Convention convention, final Locale errorLocale, final Map<Class<?>,Factory> factories)
+            final UnitFormat unitFormat, final Convention convention, final Locale errorLocale,
+            final Map<Class<?>,Factory> factories)
     {
-        super(symbols, numberFormat, dateFormat, getFactory(MathTransformFactory.class, factories), errorLocale);
+        super(symbols, numberFormat, dateFormat, unitFormat, getFactory(MathTransformFactory.class, factories), errorLocale);
         crsFactory   = getFactory(CRSFactory.class,   factories);
         csFactory    = getFactory(CSFactory.class,    factories);
         datumFactory = getFactory(DatumFactory.class, factories);
@@ -269,6 +276,7 @@ final class GeodeticObjectParser extends
                     verticalElements = verticalElements.complete(crsFactory, csFactory);
                 } catch (FactoryException e) {
                     if (ex == null) ex = e;
+                    else ex.addSuppressed(e);
                 }
                 if (verticalElements != null) {
                     warning(Errors.formatInternational(Errors.Keys.CanNotAssignUnitToDimension_2,
@@ -400,7 +408,7 @@ final class GeodeticObjectParser extends
             /*
              * Example: SCOPE["Large scale topographic mapping and cadastre."]
              */
-            element = parent.pullOptionalElement(WKTKeywords.Scope, null);
+            element = parent.pullOptionalElement(WKTKeywords.Scope);
             if (element != null) {
                 properties.put(ReferenceSystem.SCOPE_KEY, element.pullString("scope"));  // Other types like Datum use the same key.
                 element.close(ignoredElements);
@@ -409,7 +417,7 @@ final class GeodeticObjectParser extends
              * Example: AREA["Netherlands offshore."]
              */
             DefaultExtent extent = null;
-            while ((element = parent.pullOptionalElement(WKTKeywords.Area, null)) != null) {
+            while ((element = parent.pullOptionalElement(WKTKeywords.Area)) != null) {
                 final String area = element.pullString("area");
                 element.close(ignoredElements);
                 if (extent == null) extent = new DefaultExtent();
@@ -418,7 +426,7 @@ final class GeodeticObjectParser extends
             /*
              * Example: BBOX[51.43, 2.54, 55.77, 6.40]
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.BBox, null)) != null) {
+            while ((element = parent.pullOptionalElement(WKTKeywords.BBox)) != null) {
                 final double southBoundLatitude = element.pullDouble("southBoundLatitude");
                 final double westBoundLongitude = element.pullDouble("westBoundLongitude");
                 final double northBoundLatitude = element.pullDouble("northBoundLatitude");
@@ -433,11 +441,12 @@ final class GeodeticObjectParser extends
              *
              * Units are optional, default to metres (no "contextual units" here).
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.VerticalExtent, null)) != null) {
+            while ((element = parent.pullOptionalElement(WKTKeywords.VerticalExtent)) != null) {
                 final double minimum = element.pullDouble("minimum");
                 final double maximum = element.pullDouble("maximum");
-                final Unit<Length> unit = parseUnit(element, WKTKeywords.LengthUnit, SI.METRE);
+                Unit<Length> unit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
                 element.close(ignoredElements);
+                if (unit   == null) unit   = SI.METRE;
                 if (extent == null) extent = new DefaultExtent();
                 verticalElements = new VerticalInfo(verticalElements, extent, minimum, maximum, unit).resolve(verticalCRS);
             }
@@ -450,7 +459,7 @@ final class GeodeticObjectParser extends
              * This operation requires the the sis-temporal module. If not available,
              * we will report a warning and leave the temporal extent missing.
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.TimeExtent, null)) != null) {
+            while ((element = parent.pullOptionalElement(WKTKeywords.TimeExtent)) != null) {
                 final Date startTime = element.pullDate("startTime");
                 final Date endTime   = element.pullDate("endTime");
                 element.close(ignoredElements);
@@ -469,7 +478,7 @@ final class GeodeticObjectParser extends
     }
 
     /**
-     * Parses an optional {@code "UNIT"} element.
+     * Parses an optional {@code "UNIT"} element of a known dimension.
      * This element has the following pattern:
      *
      * {@preformat text
@@ -480,29 +489,52 @@ final class GeodeticObjectParser extends
      * in each {@code AXIS[…]} element instead than for the whole coordinate system.
      *
      * @param  parent   The parent element.
-     * @param  keyword  The unit keyword.
+     * @param  keyword  The unit keyword (e.g. {@code "LengthUnit"} or {@code "AngleUnit"}).
      * @param  baseUnit The base unit, usually {@code SI.METRE} or {@code SI.RADIAN}.
-     * @return The {@code "UNIT"} element as an {@link Unit} object.
+     * @return The {@code "UNIT"} element as an {@link Unit} object, or {@code null} if none.
      * @throws ParseException if the {@code "UNIT"} can not be parsed.
      *
      * @todo Authority code is currently ignored. We may consider to create a subclass of
      *       {@link Unit} which implements {@link IdentifiedObject} in a future version.
      */
-    @SuppressWarnings("unchecked")
-    private <Q extends Quantity> Unit<Q> parseUnit(final Element parent, final String keyword, final Unit<Q> baseUnit)
-            throws ParseException
+    private <Q extends Quantity> Unit<Q> parseDerivedUnit(final Element parent,
+            final String keyword, final Unit<Q> baseUnit) throws ParseException
     {
         final Element element = parent.pullOptionalElement(keyword, WKTKeywords.Unit);
         if (element == null) {
-            return baseUnit.equals(SI.RADIAN) ? (Unit<Q>) NonSI.DEGREE_ANGLE : baseUnit;
+            return null;
         }
-        final String  name   = element.pullString("name");
-        final double  factor = element.pullDouble("factor");
+        final String name   = element.pullString("name");
+        final double factor = element.pullDouble("factor");
         parseMetadataAndClose(element, name);
         return Units.multiply(baseUnit, factor);
     }
 
     /**
+     * Parses an optional {@code "UNIT"} element of unknown dimension.
+     * This method tries to infer the quantity dimension from the unit keyword.
+     *
+     * @param  parent The parent element.
+     * @return The {@code "UNIT"} element, or {@code null} if none.
+     * @throws ParseException if the {@code "UNIT"} can not be parsed.
+     */
+    private Unit<?> parseUnit(final Element parent) throws ParseException {
+        final Element element = parent.pullOptionalElement(UNIT_KEYWORDS);
+        if (element == null) {
+            return null;
+        }
+        final String name   = element.pullString("name");
+        final double factor = element.pullDouble("factor");
+        final int    index  = element.getKeywordIndex();
+        parseMetadataAndClose(element, name);
+        if (index != 0) {
+            return Units.multiply(BASE_UNITS[index - 1], factor);
+        }
+        // If we can not infer the base type, we have to rely on the name.
+        return parseUnit(name);
+    }
+
+    /**
      * Parses an {@code "AXIS"} element.
      * This element has the following pattern:
      *
@@ -517,20 +549,20 @@ final class GeodeticObjectParser extends
      *
      * @param  parent       The parent element.
      * @param  isGeographic {@code true} if the parent element is a geodetic CRS having an ellipsoidal coordinate system.
-     * @param  unit         The contextual unit, usually {@code SI.METRE} or {@code SI.RADIAN}.
+     * @param  defaultUnit  The contextual unit (usually {@code SI.METRE} or {@code SI.RADIAN}), or {@code null} if unknown.
      * @param  mandatory    {@code true} if the axis is mandatory, or {@code false} if it is optional.
      * @return The {@code "AXIS"} element as a {@link CoordinateSystemAxis} object, or {@code null}
      *         if the axis was not required and there is no axis object.
      * @throws ParseException if the {@code "AXIS"} element can not be parsed.
      */
     private CoordinateSystemAxis parseAxis(final Element parent, final boolean isGeographic,
-            final Unit<?> unit, final boolean mandatory) throws ParseException
+            final Unit<?> defaultUnit, final boolean mandatory) throws ParseException
     {
         final Element element;
         if (mandatory) {
             element = parent.pullElement(WKTKeywords.Axis);
         } else {
-            element = parent.pullOptionalElement(WKTKeywords.Axis, null);
+            element = parent.pullOptionalElement(WKTKeywords.Axis);
             if (element == null) {
                 return null;
             }
@@ -550,6 +582,13 @@ final class GeodeticObjectParser extends
             }
         }
         final Element orientation = element.pullVoidElement("orientation");
+        Unit<?> unit = parseUnit(element);
+        if (unit == null) {
+            if (defaultUnit == null) {
+                throw element.missingComponent(WKTKeywords.Unit);
+            }
+            unit = defaultUnit;
+        }
         final AxisDirection direction = Types.forCodeName(AxisDirection.class, orientation.keyword, mandatory);
         /*
          * According ISO 19162, the abbreviation should be inserted between parenthesis in the name.
@@ -613,6 +652,9 @@ final class GeodeticObjectParser extends
         final Element element   = parent.pullElement(WKTKeywords.PrimeM);
         final String  name      = element.pullString("name");
         final double  longitude = element.pullDouble("longitude");
+        if (angularUnit == null) {
+            throw element.missingComponent(WKTKeywords.AngleUnit);
+        }
         try {
             return datumFactory.createPrimeMeridian(parseMetadataAndClose(element, name), longitude, angularUnit);
         } catch (FactoryException exception) {
@@ -634,7 +676,7 @@ final class GeodeticObjectParser extends
      * @throws ParseException if the {@code "TOWGS84"} can not be parsed.
      */
     private Object parseToWGS84(final Element parent) throws ParseException {
-        final Element element = parent.pullOptionalElement(WKTKeywords.ToWGS84, null);
+        final Element element = parent.pullOptionalElement(WKTKeywords.ToWGS84);
         if (element == null) {
             return null;
         }
@@ -830,7 +872,7 @@ final class GeodeticObjectParser extends
         final Element          element    = parent.pullElement(WKTKeywords.Local_CS);
         final String           name       = element.pullString("name");
         final EngineeringDatum datum      = parseLocalDatum(element);
-        final Unit<Length>     linearUnit = parseUnit(element, WKTKeywords.LengthUnit, SI.METRE);
+        final Unit<Length>     linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         CoordinateSystemAxis   axis       = parseAxis(element, false, linearUnit, true);
         final List<CoordinateSystemAxis> list = new ArrayList<>();
         do {
@@ -863,7 +905,7 @@ final class GeodeticObjectParser extends
         final String        name       = element.pullString("name");
         final PrimeMeridian meridian   = parsePrimem(element, NonSI.DEGREE_ANGLE);
         final GeodeticDatum datum      = parseDatum (element, meridian);
-        final Unit<Length>  linearUnit = parseUnit  (element, WKTKeywords.LengthUnit, SI.METRE);
+        final Unit<Length>  linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         CartesianCS cs;
         CoordinateSystemAxis axis0, axis1 = null, axis2 = null;
         axis0 = parseAxis(element, false, linearUnit, false);
@@ -877,6 +919,9 @@ final class GeodeticObjectParser extends
                 cs = csFactory.createCartesianCS(properties, axis0, axis1, axis2);
                 cs = referencing.upgradeGeocentricCS(cs);
             } else {
+                if (linearUnit == null) {
+                    throw element.missingComponent(WKTKeywords.Unit);
+                }
                 cs = referencing.getGeocentricCS(linearUnit);
             }
             return crsFactory.createGeocentricCRS(properties, datum, cs);
@@ -901,10 +946,13 @@ final class GeodeticObjectParser extends
         final Element        element    = parent.pullElement(WKTKeywords.Vert_CS);
         final String         name       = element.pullString("name");
         final VerticalDatum  datum      = parseVertDatum(element);
-        final Unit<Length>   linearUnit = parseUnit(element, WKTKeywords.LengthUnit, SI.METRE);
+        final Unit<Length>   linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         CoordinateSystemAxis axis       = parseAxis(element, false, linearUnit, false);
         try {
             if (isAxisIgnored(axis)) {
+                if (linearUnit == null) {
+                    throw element.missingComponent(WKTKeywords.Unit);
+                }
                 String sn = "Height", abbreviation = "h";
                 AxisDirection direction = AxisDirection.UP;
                 final VerticalDatumType type = datum.getVerticalDatumType();
@@ -946,10 +994,13 @@ final class GeodeticObjectParser extends
         final Element        element  = parent.pullElement(WKTKeywords.TimeCRS);
         final String         name     = element.pullString("name");
         final TemporalDatum  datum    = parseTimeDatum(element);
-        final Unit<Duration> timeUnit = parseUnit(element, WKTKeywords.TimeUnit, SI.SECOND);
+        final Unit<Duration> timeUnit = parseDerivedUnit(element, WKTKeywords.TimeUnit, SI.SECOND);
         CoordinateSystemAxis axis     = parseAxis(element, false, timeUnit, false);
         try {
             if (isAxisIgnored(axis)) {
+                if (timeUnit == null) {
+                    throw element.missingComponent(WKTKeywords.TimeUnit);
+                }
                 axis = createAxis("Time", "t", AxisDirection.FUTURE, timeUnit);
             }
             return crsFactory.createTemporalCRS(parseMetadataAndClose(element, name), datum,
@@ -973,7 +1024,7 @@ final class GeodeticObjectParser extends
     private GeographicCRS parseGeoGCS(final Element parent) throws ParseException {
         final Element       element     = parent.pullElement(WKTKeywords.GeogCS);
               Object        name        = element.pullString("name");
-        final Unit<Angle>   angularUnit = parseUnit  (element, WKTKeywords.AngleUnit, SI.RADIAN);
+        final Unit<Angle>   angularUnit = parseDerivedUnit(element, WKTKeywords.AngleUnit, SI.RADIAN);
         final PrimeMeridian meridian    = parsePrimem(element, angularUnit);
         final GeodeticDatum datum       = parseDatum (element, meridian);
         if (((String) name).isEmpty()) {
@@ -991,6 +1042,9 @@ final class GeodeticObjectParser extends
                 axis1 = parseAxis(element, true, angularUnit, true);
             }
             if (isAxisIgnored(axis0)) {
+                if (angularUnit == null) {
+                    throw element.missingComponent(WKTKeywords.AngleUnit);
+                }
                 axis0 = createAxis(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST,  angularUnit);
                 axis1 = createAxis(AxisNames.GEODETIC_LATITUDE,  "φ", AxisDirection.NORTH, angularUnit);
             }
@@ -1019,7 +1073,7 @@ final class GeodeticObjectParser extends
         final Element       element    = parent.pullElement(WKTKeywords.ProjCS);
         final String        name       = element.pullString("name");
         final GeographicCRS geoCRS     = parseGeoGCS(element);
-        final Unit<Length>  linearUnit = parseUnit(element, WKTKeywords.LengthUnit, SI.METRE);
+        final Unit<Length>  linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         final boolean  usesCommonUnits = convention.usesCommonUnits;
         final Conversion    conversion = parseProjection(element,
                 usesCommonUnits ? SI.METRE : linearUnit,
@@ -1031,6 +1085,9 @@ final class GeodeticObjectParser extends
                 axis1 = parseAxis(element, false, linearUnit, true);
             }
             if (isAxisIgnored(axis0)) {
+                if (linearUnit == null) {
+                    throw element.missingComponent(WKTKeywords.LengthUnit);
+                }
                 axis0 = createAxis(AxisNames.EASTING,  "E", AxisDirection.EAST,  linearUnit);
                 axis1 = createAxis(AxisNames.NORTHING, "N", AxisDirection.NORTH, linearUnit);
             }

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -21,6 +21,7 @@ import java.text.DateFormat;
 import java.text.NumberFormat;
 import java.text.ParseException;
 import javax.measure.unit.Unit;
+import javax.measure.unit.UnitFormat;
 import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
 import org.opengis.util.FactoryException;
@@ -94,7 +95,7 @@ class MathTransformParser extends Abstra
      * @param mtFactory The factory to use to create {@link MathTransform} objects.
      */
     public MathTransformParser(final MathTransformFactory mtFactory) {
-        this(Symbols.getDefault(), null, null, mtFactory, null);
+        this(Symbols.getDefault(), null, null, null, mtFactory, null);
     }
 
     /**
@@ -103,13 +104,14 @@ class MathTransformParser extends Abstra
      * @param symbols       The set of symbols to use.
      * @param numberFormat  The number format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param dateFormat    The date format provided by {@link WKTFormat}, or {@code null} for a default format.
+     * @param unitFormat    The unit format provided by {@link WKTFormat}, or {@code null} for a default format.
      * @param mtFactory     The factory to use to create {@link MathTransform} objects.
      * @param errorLocale   The locale for error messages (not for parsing), or {@code null} for the system default.
      */
     MathTransformParser(final Symbols symbols, final NumberFormat numberFormat, final DateFormat dateFormat,
-            final MathTransformFactory mtFactory, final Locale errorLocale)
+            final UnitFormat unitFormat, final MathTransformFactory mtFactory, final Locale errorLocale)
     {
-        super(symbols, numberFormat, dateFormat, errorLocale);
+        super(symbols, numberFormat, dateFormat, unitFormat, errorLocale);
         this.mtFactory = mtFactory;
         ensureNonNull("mtFactory", mtFactory);
     }
@@ -168,7 +170,7 @@ class MathTransformParser extends Abstra
     {
         Element param = element;
         try {
-            while ((param = element.pullOptionalElement(WKTKeywords.Parameter, null)) != null) {
+            while ((param = element.pullOptionalElement(WKTKeywords.Parameter)) != null) {
                 final String                 name       = param.pullString("name");
                 final ParameterValue<?>      parameter  = parameters.parameter(name);
                 final ParameterDescriptor<?> descriptor = parameter.getDescriptor();

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -25,15 +25,35 @@ import org.opengis.util.FactoryException
  * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform Math Transforms} or geometric
  * objects for instance.
  *
+ * <p>Parsing services may be provided by factories which implement this interface:</p>
+ * <ul>
+ *   <li>{@link org.apache.sis.referencing.factory.GeodeticObjectFactory#createFromWKT(String)}</li>
+ *   <li>{@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createFromWKT(String)}</li>
+ * </ul>
+ *
+ * Similar services are also available as convenience static methods:
+ * <ul>
+ *   <li>{@link org.apache.sis.referencing.CRS#fromWKT(String)}</li>
+ *   <li>{@link org.apache.sis.geometry.Envelopes#fromWKT(CharSequence)}</li>
+ * </ul>
+ *
+ * <div class="section">Axis names</div>
+ * The WKT 1 specification defined axis names different than the ISO 19111 ones.
+ * This SIS parser replaces the WKT 1 names by the ISO names and abbreviations when possible.
+ *
+ * <table class="sis">
+ *   <caption>Coordinate system axis names</caption>
+ *   <tr><th>CRS type</th>   <th>WKT1 names</th>                               <th>ISO abbreviations</th></tr>
+ *   <tr><td>Geographic</td> <td>Lon, Lat</td>                                 <td>λ, φ</td></tr>
+ *   <tr><td>Vertical</td>   <td><var>H</var></td>                             <td><var>H</var> or <var>h</var></td></tr>
+ *   <tr><td>Projected</td>  <td><var>X</var>, <var>Y</var></td>               <td><var>E</var>, <var>N</var></td></tr>
+ *   <tr><td>Geocentric</td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td></tr>
+ * </table>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
  * @version 0.6
  * @module
- *
- * @see org.opengis.referencing.crs.CRSFactory#createFromWKT(String)
- * @see org.opengis.referencing.operation.MathTransformFactory#createFromWKT(String)
- * @see org.apache.sis.referencing.CRS#fromWKT(String)
- * @see org.apache.sis.geometry.Envelopes#fromWKT(CharSequence)
  */
 public interface Parser {
     /**

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -45,7 +45,11 @@ import org.apache.sis.metadata.iso.exten
  * But {@code DefaultVerticalExtent} has no {@code unit} property. Instead, {@code DefaultVerticalExtent} has a
  * {@code verticalCRS} property. The WKT specification said that heights are positive toward up and relative to
  * an unspecified mean sea level, but we will try to use the parsed vertical CRS instance if we find a suitable
- * one.
+ * one (i.e. one that defines gravity-related heights or depths), on the assumption that the vertical extent is
+ * likely to be defined in the same vertical CRS.
+ *
+ * <p>This class can be understood as the converse of
+ * {@link org.apache.sis.metadata.iso.extent.Extents#getVerticalRange}</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -524,6 +524,7 @@ public class WKTFormat extends CompoundF
             this.parser = parser = new GeodeticObjectParser(symbols,
                     (NumberFormat) getFormat(Number.class),
                     (DateFormat)   getFormat(Date.class),
+                    (UnitFormat)   getFormat(Unit.class),
                     convention, getLocale(), factories);
         }
         Object object = null;

Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -40,7 +40,7 @@ public final strictfp class ElementTest
     /**
      * A dummy parser to be given to the {@link Element} constructor.
      */
-    private final AbstractParser parser = new AbstractParser(Symbols.SQUARE_BRACKETS, null, null, Locale.ENGLISH) {
+    private final AbstractParser parser = new AbstractParser(Symbols.SQUARE_BRACKETS, null, null, null, Locale.ENGLISH) {
         @Override Object parseObject(Element element) throws ParseException {
             throw new UnsupportedOperationException();
         }

Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.Arrays;
 import java.util.Collections;
 import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
 import javax.measure.converter.UnitConverter;
 import javax.measure.converter.ConversionException;
 import org.opengis.metadata.extent.GeographicBoundingBox;
@@ -56,28 +57,37 @@ public final strictfp class ExtentsTest
      * @throws ConversionException should never happen in this test.
      */
     @Test
+    @SuppressWarnings("null")
     public void testGetVerticalRange() throws ConversionException {
         final List<DefaultVerticalExtent> extents = Arrays.asList(
                 new DefaultVerticalExtent( -200,  -100, VerticalCRSMock.HEIGHT),
                 new DefaultVerticalExtent(  150,   300, VerticalCRSMock.DEPTH),
                 new DefaultVerticalExtent(  0.1,   0.2, VerticalCRSMock.SIGMA_LEVEL),
-                new DefaultVerticalExtent( -600,  -300, VerticalCRSMock.HEIGHT_ft), // [91.44 182.88] metres
+                new DefaultVerticalExtent( -600,  -300, VerticalCRSMock.HEIGHT_ft), // [91.44 … 182.88] metres
                 new DefaultVerticalExtent(10130, 20260, VerticalCRSMock.BAROMETRIC_HEIGHT)
         );
         Collections.shuffle(extents, TestUtilities.createRandomNumberGenerator());
-        final DefaultExtent extent = new DefaultExtent();
-        extent.setVerticalElements(extents);
         /*
-         * Since we have shuffled the vertical extents in random order, the range obtained below
-         * may be either in metres or in feet (depending which vertical extent appear first).
-         * Consequently our test will need to convert the values to metres.
+         * Since we have shuffled the vertical extents in random order, the range that we will
+         * test may be either in metres or in feet depending on which vertical extent is first.
+         * So we need to check which linear unit is first.
+         */
+        Unit<?> unit = null;
+        for (final DefaultVerticalExtent e : extents) {
+            unit = e.getVerticalCRS().getCoordinateSystem().getAxis(0).getUnit();
+            if (Units.isLinear(unit)) break;
+        }
+        final UnitConverter c = unit.getConverterToAny(SI.METRE);
+        /*
+         * The actual test. Arbitrarily compare the heights in metres, converting them if needed.
          */
+        final DefaultExtent extent = new DefaultExtent();
+        extent.setVerticalElements(extents);
         final MeasurementRange<Double> range = Extents.getVerticalRange(extent);
         assertNotNull("getVerticalRange", range);
-        assertTrue("unit", Units.isLinear(range.unit()));
-        final UnitConverter c = range.unit().getConverterToAny(SI.METRE);
-        assertEquals("minimum", -300,   c.convert(range.getMinDouble()), 0.001);
-        assertEquals("maximum", -91.44, c.convert(range.getMaxDouble()), 0.001);
+        assertSame   ("unit",    unit,    range.unit());
+        assertEquals ("minimum", -300,    c.convert(range.getMinDouble()), 0.001);
+        assertEquals ("maximum", -91.44,  c.convert(range.getMaxDouble()), 0.001);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -90,7 +90,7 @@ public final strictfp class GeodeticObje
      */
     private void setConvention(final Convention convention) {
         final GeodeticObjectParser p = parser;
-        parser = new GeodeticObjectParser(p.symbols, null, null, convention, p.errorLocale, null);
+        parser = new GeodeticObjectParser(p.symbols, null, null, null, convention, p.errorLocale, null);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java?rev=1685763&r1=1685762&r2=1685763&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] Tue Jun 16 11:28:28 2015
@@ -166,12 +166,12 @@ public final class Units extends Static
      *
      * @see #isAngular(Unit)
      */
-    @SuppressWarnings({"unchecked","rawtypes"})
+    @SuppressWarnings("unchecked")
     public static Unit<Angle> ensureAngular(final Unit<?> unit) throws IllegalArgumentException {
         if (unit != null && !isAngular(unit)) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.NonAngularUnit_1, unit));
         }
-        return (Unit) unit;
+        return (Unit<Angle>) unit;
     }
 
     /**
@@ -184,12 +184,12 @@ public final class Units extends Static
      *
      * @see #isLinear(Unit)
      */
-    @SuppressWarnings({"unchecked","rawtypes"})
+    @SuppressWarnings("unchecked")
     public static Unit<Length> ensureLinear(final Unit<?> unit) throws IllegalArgumentException {
         if (unit != null && !isLinear(unit)) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.NonLinearUnit_1, unit));
         }
-        return (Unit) unit;
+        return (Unit<Length>) unit;
     }
 
     /**
@@ -202,12 +202,12 @@ public final class Units extends Static
      *
      * @see #isTemporal(Unit)
      */
-    @SuppressWarnings({"unchecked","rawtypes"})
+    @SuppressWarnings("unchecked")
     public static Unit<Duration> ensureTemporal(final Unit<?> unit) throws IllegalArgumentException {
         if (unit != null && !isTemporal(unit)) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.NonTemporalUnit_1, unit));
         }
-        return (Unit) unit;
+        return (Unit<Duration>) unit;
     }
 
     /**
@@ -220,12 +220,12 @@ public final class Units extends Static
      *
      * @see #isScale(Unit)
      */
-    @SuppressWarnings({"unchecked","rawtypes"})
+    @SuppressWarnings("unchecked")
     public static Unit<Dimensionless> ensureScale(final Unit<?> unit) throws IllegalArgumentException {
         if (unit != null && !isScale(unit)) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.NonScaleUnit_1, unit));
         }
-        return (Unit) unit;
+        return (Unit<Dimensionless>) unit;
     }
 
     /**
@@ -248,14 +248,14 @@ public final class Units extends Static
      * @return The unit multiplied by the given factor.
      */
     @Workaround(library="JSR-275", version="0.9.3")
-    @SuppressWarnings({"unchecked","rawtypes"})
+    @SuppressWarnings("unchecked")
     public static <A extends Quantity> Unit<A> multiply(Unit<A> unit, final double factor) {
         if (SI.RADIAN.equals(unit)) {
             if (abs(factor - (PI / 180)) <= (EPS * PI/180)) {
-                return (Unit) NonSI.DEGREE_ANGLE;
+                return (Unit<A>) NonSI.DEGREE_ANGLE;
             }
             if (abs(factor - (PI / 200)) <= (EPS * PI/200)) {
-                return (Unit) NonSI.GRADE;
+                return (Unit<A>) NonSI.GRADE;
             }
         }
         if (abs(factor - 1) > EPS) {



Mime
View raw message