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 aeaadf2f05 GeoTIFF writer should throw an exception instead of logging a warning when the CRS or the "grid to CRS" transform cannot be encoded. aeaadf2f05 is described below commit aeaadf2f05a610a22af587cc7581adf335f5f404 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Tue Dec 17 16:17:03 2024 +0100 GeoTIFF writer should throw an exception instead of logging a warning when the CRS or the "grid to CRS" transform cannot be encoded. --- .../apache/sis/storage/geotiff/GeoTiffStore.java | 6 +- .../sis/storage/geotiff/writer/GeoEncoder.java | 115 +++++++++++---------- .../sis/storage/IncompatibleResourceException.java | 56 +++++++++- .../sis/storage/base/WritableAggregateSupport.java | 2 +- .../storage/base/WritableGridCoverageSupport.java | 6 +- .../apache/sis/storage/esri/AsciiGridStore.java | 27 ++--- .../org/apache/sis/storage/esri/WritableStore.java | 4 +- .../apache/sis/storage/image/WritableStore.java | 27 ++--- .../apache/sis/storage/geopackage/GpkgStore.java | 2 +- 9 files changed, 151 insertions(+), 94 deletions(-) diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java index 0c5cd17ce6..5dabda1abe 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java @@ -683,8 +683,8 @@ public class GeoTiffStore extends DataStore implements Aggregate { * @param metadata title, author and other information, or {@code null} if none. * @return the effectively added resource. Using this resource may cause data to be reloaded. * @throws ReadOnlyStorageException if this data store is read-only. - * @throws DataStoreException if the given {@code image} has a property which is not supported by this writer, - * or if an error occurred while writing to the output stream. + * @throws IncompatibleResourceException if the given {@code image} has a property which is not supported by this writer. + * @throws DataStoreException if an error occurred while writing to the output stream. * * @since 1.5 */ @@ -708,7 +708,7 @@ public class GeoTiffStore extends DataStore implements Aggregate { } index = writer.imageIndex++; } catch (RasterFormatException | ArithmeticException e) { - throw new IncompatibleResourceException(cannotWrite(), e); + throw new IncompatibleResourceException(cannotWrite(), e).addAspect("raster"); } catch (IOException e) { throw new DataStoreException(cannotWrite(), e); } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java index a88c8b21d4..25536bca7b 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java @@ -34,6 +34,7 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.GeodeticCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.VerticalCRS; +import org.opengis.referencing.crs.EngineeringCRS; import org.opengis.referencing.cs.AxisDirection; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CartesianCS; @@ -63,6 +64,7 @@ import org.apache.sis.referencing.privy.WKTKeywords; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.PixelInCell; import org.apache.sis.coverage.grid.IncompleteGridGeometryException; +import org.apache.sis.storage.IncompatibleResourceException; import org.apache.sis.storage.base.MetadataFetcher; import org.apache.sis.storage.geotiff.base.UnitKey; import org.apache.sis.storage.geotiff.base.GeoKeys; @@ -223,26 +225,31 @@ public final class GeoEncoder { * @throws ArithmeticException if a short value cannot be stored as an unsigned 16 bits integer. * @throws IncommensurableException if a measure uses an unexpected unit of measurement. * @throws IncompleteGridGeometryException if the grid geometry is incomplete. + * @throws IncompatibleResourceException if the grid geometry cannot be encoded. */ public void write(final GridGeometry grid, final MetadataFetcher<?> metadata) - throws FactoryException, IncommensurableException + throws FactoryException, IncommensurableException, IncompatibleResourceException { citation = CollectionsExt.first(metadata.transformationDimension); isPoint = CollectionsExt.first(metadata.cellGeometry) == CellGeometry.POINT; gridToCRS = MathTransforms.getMatrix(grid.getGridToCRS(isPoint ? PixelInCell.CELL_CENTER : PixelInCell.CELL_CORNER)); if (gridToCRS == null) { - warning(resources().getString(Resources.Keys.CanNotEncodeNonLinearModel), null); + String message = resources().getString(Resources.Keys.CanNotEncodeNonLinearModel); + throw new IncompatibleResourceException(message).addAspect("gridToCRS"); } if (grid.isDefined(GridGeometry.CRS)) { fullCRS = grid.getCoordinateReferenceSystem(); final CoordinateReferenceSystem crs = CRS.getHorizontalComponent(fullCRS); - if ((crs instanceof ProjectedCRS && writeCRS((ProjectedCRS) crs)) || - (crs instanceof GeodeticCRS && writeCRS((GeodeticCRS) crs, false))) - { + if (crs instanceof ProjectedCRS) { + writeCRS((ProjectedCRS) crs); writeCRS(CRS.getVerticalComponent(fullCRS, true)); - } else { - unsupportedType(fullCRS); + } else if (crs instanceof GeodeticCRS) { + writeCRS((GeodeticCRS) crs, false); + writeCRS(CRS.getVerticalComponent(fullCRS, true)); + } else if (fullCRS instanceof EngineeringCRS && ReferencingUtilities.getDimension(fullCRS) == 2) { writeModelType(GeoCodes.userDefined); + } else { + throw unsupportedType(fullCRS); } } else { writeModelType(GeoCodes.undefined); @@ -270,8 +277,9 @@ public final class GeoEncoder { * * @param crs the CRS to write, or {@code null} if none. * @throws FactoryException if an error occurred while fetching an EPSG code. + * @throws IncompatibleResourceException if a unit of measurement cannot be encoded. */ - private void writeCRS(final VerticalCRS crs) throws FactoryException { + private void writeCRS(final VerticalCRS crs) throws FactoryException, IncompatibleResourceException { if (crs != null) { hasVerticalAxis = true; if (writeEPSG(GeoKeys.Vertical, crs)) { @@ -298,24 +306,25 @@ public final class GeoEncoder { * * @param crs the CRS to write. * @param isBaseCRS whether to write the base CRS of a projected CRS. - * @return whether this method has been able to write the CRS. * @throws FactoryException if an error occurred while fetching an EPSG code. * @throws IncommensurableException if a measure uses an unexpected unit of measurement. + * @throws IncompatibleResourceException if the <abbr>CRS</abbr> has an incompatible property. */ - private boolean writeCRS(final GeodeticCRS crs, final boolean isBaseCRS) throws FactoryException, IncommensurableException { + private void writeCRS(final GeodeticCRS crs, final boolean isBaseCRS) + throws FactoryException, IncommensurableException, IncompatibleResourceException + { final short type; final CoordinateSystem cs = crs.getCoordinateSystem(); addUnits(UnitKey.ANGULAR, cs); if (cs instanceof EllipsoidalCS) { type = GeoCodes.ModelTypeGeographic; } else if (isBaseCRS) { - warning(resources().getString(Resources.Keys.CanNotEncodeNonGeographicBase), null); - return false; + String message = resources().getString(Resources.Keys.CanNotEncodeNonGeographicBase); + throw new IncompatibleResourceException(message).addAspect("crs"); } else if (cs instanceof CartesianCS) { type = GeoCodes.ModelTypeGeocentric; } else { - unsupportedType(cs); - return false; + throw unsupportedType(cs); } /* * Start writing GeoTIFF keys for the geodetic CRS, potentially followed by datum, prime meridian and ellipsoid @@ -361,7 +370,6 @@ public final class GeoEncoder { } else if (isBaseCRS) { writeUnit(UnitKey.ANGULAR); // Map projection parameters may need this unit. } - return true; } /** @@ -371,23 +379,27 @@ public final class GeoEncoder { * @return whether this method has been able to write the CRS. * @throws FactoryException if an error occurred while fetching an EPSG or GeoTIFF code. * @throws IncommensurableException if a measure uses an unexpected unit of measurement. + * @throws IncompatibleResourceException if the <abbr>CRS</abbr> has an incompatible property. */ - private boolean writeCRS(final ProjectedCRS crs) throws FactoryException, IncommensurableException { - if (!writeCRS(crs.getBaseCRS(), true)) { - return false; - } + private boolean writeCRS(final ProjectedCRS crs) + throws FactoryException, IncommensurableException, IncompatibleResourceException + { + writeCRS(crs.getBaseCRS(), true); if (writeEPSG(GeoKeys.ProjectedCRS, crs)) { writeName(GeoKeys.ProjectedCitation, null, crs); addUnits(UnitKey.PROJECTED, crs.getCoordinateSystem()); final Conversion projection = crs.getConversionFromBase(); if (writeEPSG(GeoKeys.Projection, projection)) { final var method = projection.getMethod(); - final short projCode = getGeoCode(method); + final short projCode = getGeoCode(0, method); writeShort(GeoKeys.ProjMethod, projCode); writeUnit(UnitKey.PROJECTED); switch (projCode) { - case GeoCodes.undefined: missingValue(GeoKeys.ProjMethod); return true; - case GeoCodes.userDefined: cannotEncode(0, name(method), null); break; + case GeoCodes.userDefined: // Should not happen. + case GeoCodes.undefined: { + missingValue(GeoKeys.ProjMethod); + return true; + } /* * TODO: GeoTIFF requirement 27.4 said that ProjectedCitationGeoKey shall be provided, * But how? Using the same multiple-names convention ("GCS Name") as for geodetic CRS? @@ -400,12 +412,12 @@ public final class GeoEncoder { RuntimeException cause = null; final var descriptor = p.getDescriptor(); if (p instanceof ParameterValue<?>) { - final short key = getGeoCode(descriptor); + final short key = getGeoCode(1, descriptor); if (key != GeoCodes.undefined && key != GeoCodes.userDefined) { final var pv = (ParameterValue<?>) p; final UnitKey type = UnitKey.ofProjectionParameter(key); if (type == UnitKey.LINEAR) { - continue; // Skip the "cannot encode" warning. + continue; // Skip the "cannot encode" error. } if (type != UnitKey.NULL) try { final Unit<?> unit = units.getOrDefault(type, type.defaultUnit()); @@ -416,7 +428,7 @@ public final class GeoEncoder { } } } - cannotEncode(1, name(descriptor), cause); + throw cannotEncode(1, name(descriptor), cause); } } return true; @@ -428,18 +440,20 @@ public final class GeoEncoder { * * @param main the main kind of units expected in the coordinate system. * @param cs the coordinate system to analyze. + * @throws IncompatibleResourceException if the unit of measurement cannot be encoded. */ - private void addUnits(final UnitKey main, final CoordinateSystem cs) { + private void addUnits(final UnitKey main, final CoordinateSystem cs) throws IncompatibleResourceException { for (int i = cs.getDimension(); --i >= 0;) { final Unit<?> unit = cs.getAxis(i).getUnit(); final UnitKey type = main.validate(unit); if (type != null) { final Unit<?> previous = units.putIfAbsent(type, unit); if (previous != null && !previous.equals(unit)) { - warning(errors().getString(Errors.Keys.HeterogynousUnitsIn_1, name(cs)), null); + String message = errors().getString(Errors.Keys.HeterogynousUnitsIn_1, name(cs)); + throw new IncompatibleResourceException(message).addAspect("crs"); } } else { - cannotEncode(2, unit.toString(), null); + throw cannotEncode(2, unit.toString(), null).addAspect("unit"); } } } @@ -449,8 +463,9 @@ public final class GeoEncoder { * This method should be invoked only once per unit key. * * @param key identification of the unit to write. + * @throws IncompatibleResourceException if the unit of measurement cannot be encoded. */ - private void writeUnit(final UnitKey key) { + private void writeUnit(final UnitKey key) throws IncompatibleResourceException { final Unit<?> unit = units.get(key); if (unit != null) { final short epsg = toShortEPSG(Units.getEpsgCode(unit, key.isAxis)); @@ -460,7 +475,7 @@ public final class GeoEncoder { writeShort(key.codeKey, epsg); writeDouble(key.scaleKey, Units.toStandardUnit(unit)); } else { - cannotEncode(2, unit.toString(), null); + throw cannotEncode(2, unit.toString(), null).addAspect("unit"); } } } @@ -529,21 +544,26 @@ public final class GeoEncoder { * Fetches the GeoTIFF code of the given object. If {@code null}, returns {@link GeoCodes#undefined}. * If the object has no GeTIFF identifier, returns {@value GeoCodes#userDefined}. * + * @param type object type: 0 = operation method, 1 = parameter. * @param object the object for which to get the GeoTIFF code. * @return the GeoTIFF code, or {@link GeoCodes#undefined} or {@link GeoCodes#userDefined} if none. * @throws FactoryException if an error occurred while fetching the GeoTIFF code. + * @throws IncompatibleResourceException if the GeoTIFF identifier cannot be obtained. */ - private short getGeoCode(final IdentifiedObject object) throws FactoryException { + private short getGeoCode(final int type, final IdentifiedObject object) + throws FactoryException, IncompatibleResourceException + { if (object == null) { return GeoCodes.undefined; } final Identifier id = IdentifiedObjects.getIdentifier(object, Citations.GEOTIFF); + NumberFormatException cause = null; if (id != null) try { return Short.parseShort(id.getCode()); } catch (NumberFormatException e) { - warning(errors().getString(Errors.Keys.CanNotParse_1, IdentifiedObjects.toString(id)), e); + cause = e; } - return GeoCodes.userDefined; + throw cannotEncode(type, name(object), cause); } /** @@ -770,38 +790,29 @@ public final class GeoEncoder { * @param key the GeoKey for which we found no value. */ private void missingValue(final short key) { - warning(resources().getString(Resources.Keys.MissingGeoValue_1, GeoKeys.name(key)), null); + listeners.warning(resources().getString(Resources.Keys.MissingGeoValue_1, GeoKeys.name(key))); } /** - * Logs a warning saying that the given object cannot be encoded becasuse of its type. + * Prepares an exception saying that the given object cannot be encoded because of its type. * * @param object object that cannot be encoded. */ - private void unsupportedType(final IdentifiedObject object) { - warning(resources().getString(Resources.Keys.CanNotEncodeObjectType_1, ReferencingUtilities.getInterface(object)), null); + private IncompatibleResourceException unsupportedType(final IdentifiedObject object) { + String message = resources().getString(Resources.Keys.CanNotEncodeObjectType_1, ReferencingUtilities.getInterface(object)); + return new IncompatibleResourceException(message).addAspect("crs"); } /** - * Logs a warning saying that an object of the given name cannot be encoded. + * Prepares an exception saying that an object of the given name cannot be encoded. * * @param type object type: 0 = operation method, 1 = parameter, 2 = unit of measurement. * @param name name of the object that cannot be encoded. - * @param cause the reason why a warning occurred, or {@code null} if none. - */ - private void cannotEncode(final int type, final String name, final Exception cause) { - warning(resources().getString(Resources.Keys.CanNotEncodeNamedObject_2, type, name), cause); - } - - /** - * Reports a warning that occurred while analyzing the CRS. - * This warning may prevent readers to reconstruct the CRS correctly. - * - * @param message the warning message. - * @param cause the reason why a warning occurred, or {@code null} if none. + * @param cause the reason why an error occurred, or {@code null} if none. */ - private void warning(final String message, final Exception cause) { - listeners.warning(message, cause); + private IncompatibleResourceException cannotEncode(final int type, final String name, final Exception cause) { + String message = resources().getString(Resources.Keys.CanNotEncodeNamedObject_2, type, name); + return new IncompatibleResourceException(message, cause).addAspect("crs"); } /** diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/IncompatibleResourceException.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/IncompatibleResourceException.java index 2c8a9288a0..4540cfe6f6 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/IncompatibleResourceException.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/IncompatibleResourceException.java @@ -16,13 +16,18 @@ */ package org.apache.sis.storage; +import java.util.Set; + /** * Thrown when a write operation cannot be performed because the resource to write * is incompatible with the data store. + * For example, the file format may have restrictions that prevent the encoding of the coordinate + * reference system used by the resource. The {@link #getAspects()} method can help to identify + * which aspects (class, <abbr>CRS</abbr>, <i>etc.</i>) are the causes of the incompatibility. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.5 * @since 1.2 */ public class IncompatibleResourceException extends DataStoreException { @@ -31,6 +36,13 @@ public class IncompatibleResourceException extends DataStoreException { */ private static final long serialVersionUID = -1833794980891065300L; + /** + * Identification of which aspects are incompatible, or {@code null} if none. + * If non-null, this is usually a singleton set. + */ + @SuppressWarnings("serial") + private Set<String> aspects; + /** * Creates an exception with no cause and no details message. */ @@ -55,4 +67,46 @@ public class IncompatibleResourceException extends DataStoreException { public IncompatibleResourceException(String message, Throwable cause) { super(message, cause); } + + /** + * Adds an identification of the aspect which is the cause of the incompatibility. + * It should be the name of a property such as {@code "crs"} or {@code "gridToCRS"}. + * See {@link #getAspects()} for a list of suggested values. + * + * @param name an identification of the aspect which is incompatible. + * @return {@code this} for method call chaining. + * @since 1.5 + */ + public IncompatibleResourceException addAspect(final String name) { + if (aspects == null) { + aspects = Set.of(name); + } else { + // Inefficient, but rarely used. + final int n = aspects.size(); + String[] names = aspects.toArray(new String[n+1]); + names[n] = name; + aspects = Set.of(names); + } + return this; + } + + /** + * Returns identifications of the aspects which are causes of the incompatibility. + * Some values are: + * + * <ul> + * <li>{@code "class"}: the resources is not an instance of the class expected by the writer.</li> + * <li>{@code "crs"}: the coordinate reference system cannot be encoded.</li> + * <li>{@code "gridToCRS"}: the "grid to <abbr>CRS</abbr>" component of the grid geometry of a raster cannot be encoded.</li> + * <li>{@code "gridGeometry"}: the grid geometry of a raster cannot be encoded for reason less specific than {@code gridToCRS}.</li> + * <li>{@code "raster"}: the raster data cannot be encoded.</li> + * <li>{@code "unit"}: the unit of measurement cannot be encoded.</li> + * </ul> + * + * @return identifications of aspects which are incompatible. + * @since 1.5 + */ + public Set<String> getAspects() { + return (aspects != null) ? aspects : Set.of(); + } } diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableAggregateSupport.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableAggregateSupport.java index 6e68cd3f6d..2752231cee 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableAggregateSupport.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableAggregateSupport.java @@ -93,7 +93,7 @@ public final class WritableAggregateSupport implements Localized { if (Objects.requireNonNull(resource) instanceof GridCoverageResource) { return (GridCoverageResource) resource; } - throw new IncompatibleResourceException(message(GridCoverageResource.class, resource)); + throw new IncompatibleResourceException(message(GridCoverageResource.class, resource)).addAspect("class"); } /** diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableGridCoverageSupport.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableGridCoverageSupport.java index 37ad5a39a8..c9d27905c9 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableGridCoverageSupport.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableGridCoverageSupport.java @@ -173,7 +173,7 @@ public final class WritableGridCoverageSupport implements Localized { */ public final GridCoverage update(final GridCoverage coverage) throws DataStoreException { final GridCoverage existing = target.read(null, null); - final CoverageCombiner combiner = new CoverageCombiner(existing); + final var combiner = new CoverageCombiner(existing); try { if (!combiner.acceptAll(coverage)) { throw new ReadOnlyStorageException(canNotWrite()); @@ -196,14 +196,14 @@ public final class WritableGridCoverageSupport implements Localized { public final AffineTransform getAffineTransform2D(final GridExtent extent, final MathTransform gridToCRS) throws DataStoreException { - final TransformSeparator s = new TransformSeparator(gridToCRS); + final var s = new TransformSeparator(gridToCRS); try { s.addSourceDimensions(extent.getSubspaceDimensions(2)); return AffineTransforms2D.castOrCopy(s.separate()); } catch (FactoryException | CannotEvaluateException e) { throw new DataStoreReferencingException(canNotWrite(), e); } catch (IllegalArgumentException e) { - throw new IncompatibleResourceException(canNotWrite(), e); + throw new IncompatibleResourceException(canNotWrite(), e).addAspect("gridToCRS"); } } diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/AsciiGridStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/AsciiGridStore.java index 222f869de2..f7de0e522a 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/AsciiGridStore.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/AsciiGridStore.java @@ -65,48 +65,39 @@ import org.apache.sis.util.resources.Errors; * <th>Keyword</th> * <th>Value type</th> * <th>Obligation</th> - * </tr> - * <tr> + * </tr><tr> * <td>{@code NCOLS}</td> * <td>{@link java.lang.Integer}</td> * <td>Mandatory</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code NROWS}</td> * <td>{@link java.lang.Integer}</td> * <td>Mandatory</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code XLLCORNER} or {@code XLLCENTER}</td> * <td>{@link java.lang.Double}</td> * <td>Mandatory</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code YLLCORNER} or {@code YLLCENTER}</td> * <td>{@link java.lang.Double}</td> * <td>Mandatory</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code CELLSIZE}</td> * <td>{@link java.lang.Double}</td> * <td>Mandatory, unless an alternative below is present</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code XCELLSIZE} and {@code YCELLSIZE}</td> * <td>{@link java.lang.Double}</td> * <td>Non-standard alternative to {@code CELLSIZE}</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code XDIM} and {@code YDIM}</td> * <td>{@link java.lang.Double}</td> * <td>Non-standard alternative to {@code CELLSIZE}</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code DX} and {@code DY}</td> * <td>{@link java.lang.Double}</td> * <td>Non-standard alternative to {@code CELLSIZE}</td> - * </tr> - * <tr> + * </tr><tr> * <td>{@code NODATA_VALUE}</td> * <td>{@link java.lang.Double}</td> * <td>Optional</td> diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java index 10c0247fa9..66ca6828ea 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/WritableStore.java @@ -131,7 +131,7 @@ final class WritableStore extends AsciiGridStore implements WritableGridCoverage } final AffineTransform at = h.getAffineTransform2D(gg.getExtent(), gridToCRS); if (at.getShearX() != 0 || at.getShearY() != 0) { - throw new IncompatibleResourceException(h.rotationNotSupported(AsciiGridStoreProvider.NAME)); + throw new IncompatibleResourceException(h.rotationNotSupported(AsciiGridStoreProvider.NAME)).addAspect("gridToCRS"); } double scaleX = at.getScaleX(); double scaleY = -at.getScaleY(); @@ -144,7 +144,7 @@ final class WritableStore extends AsciiGridStore implements WritableGridCoverage * TODO: future version could support other signs, provided that * we implement `PixelIterator` for other `SequenceType` values. */ - throw new IncompatibleResourceException(h.canNotWrite()); + throw new IncompatibleResourceException(h.canNotWrite()).addAspect("gridToCRS"); } header.put(xll, x); header.put(yll, y); diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java index a55ac4c04a..cf94e852c2 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableStore.java @@ -151,9 +151,9 @@ class WritableStore extends WorldFileStore { @Override public String[] getImageFormat(final boolean asMimeType) { if (writer != null) { - final ImageWriterSpi provider = writer.getOriginatingProvider(); - if (provider != null) { - final String[] names = asMimeType ? provider.getMIMETypes() : provider.getFormatNames(); + final ImageWriterSpi codec = writer.getOriginatingProvider(); + if (codec != null) { + final String[] names = asMimeType ? codec.getMIMETypes() : codec.getFormatNames(); if (names != null) { return names; } @@ -223,8 +223,8 @@ class WritableStore extends WorldFileStore { */ if (index != MAIN_IMAGE || isMultiImages() > 1) { if (!getGridGeometry(MAIN_IMAGE).equals(gg, ComparisonMode.IGNORE_METADATA)) { - throw new IncompatibleResourceException( - resources().getString(Resources.Keys.IncompatibleGridGeometry)); + String message = resources().getString(Resources.Keys.IncompatibleGridGeometry); + throw new IncompatibleResourceException(message).addAspect("gridGeometry"); } } /* @@ -236,17 +236,17 @@ class WritableStore extends WorldFileStore { if (gg.isDefined(GridGeometry.GRID_TO_CRS)) try { gridToCRS = AffineTransforms2D.castOrCopy(gg.getGridToCRS(CELL_ANCHOR)); } catch (IllegalArgumentException e) { - throw new IncompatibleResourceException(e.getLocalizedMessage(), e); + throw new IncompatibleResourceException(e.getLocalizedMessage(), e).addAspect("gridToCRS"); } - final String suffix = super.setGridGeometry(index, gg); // May throw `ArithmeticException`. + final String suffixWLD = super.setGridGeometry(index, gg); // May throw `ArithmeticException`. /* * If the image is the main one, overwrite (possibly with same content) the previous auxiliary files. * Otherwise above checks should have ensured that the existing auxiliary files are applicable. */ - if (suffix != null) { + if (suffixWLD != null) { if (gridToCRS == null) { - deleteAuxiliaryFile(suffix); - } else try (BufferedWriter out = writeAuxiliaryFile(suffix)) { + deleteAuxiliaryFile(suffixWLD); + } else try (BufferedWriter out = writeAuxiliaryFile(suffixWLD)) { writeCoeffs: for (int i=0;; i++) { final double c; switch (i) { @@ -264,7 +264,7 @@ writeCoeffs: for (int i=0;; i++) { } writePRJ(); } - return suffix; + return suffixWLD; } /** @@ -311,7 +311,7 @@ writeCoeffs: for (int i=0;; i++) { if (domain == null) { domain = coverage.getGridGeometry(); // We are adding the first image. } - final WritableResource image = new WritableResource(this, listeners, numImages, domain); + final var image = new WritableResource(this, listeners, numImages, domain); image.write(coverage); components.added(image); // Must be invoked only after above succeeded. numImages++; @@ -335,7 +335,7 @@ writeCoeffs: for (int i=0;; i++) { public synchronized void remove(final Resource resource) throws DataStoreException { Exception cause = null; if (resource instanceof WritableResource) { - final WritableResource image = (WritableResource) resource; + final var image = (WritableResource) resource; if (image.store() == this) try { final int imageIndex = image.getImageIndex(); writer().removeImage(imageIndex); @@ -376,6 +376,7 @@ writeCoeffs: for (int i=0;; i++) { */ @Override ImageReader prepareReader(ImageReader current) throws IOException { + @SuppressWarnings("LocalVariableHidesMemberVariable") final ImageWriter writer = this.writer; if (writer != null) { final Object output = writer.getOutput(); diff --git a/incubator/src/org.apache.sis.storage.geopackage/main/org/apache/sis/storage/geopackage/GpkgStore.java b/incubator/src/org.apache.sis.storage.geopackage/main/org/apache/sis/storage/geopackage/GpkgStore.java index ea4db47c69..dc3f7b2eaa 100644 --- a/incubator/src/org.apache.sis.storage.geopackage/main/org/apache/sis/storage/geopackage/GpkgStore.java +++ b/incubator/src/org.apache.sis.storage.geopackage/main/org/apache/sis/storage/geopackage/GpkgStore.java @@ -371,7 +371,7 @@ public class GpkgStore extends SQLStore implements WritableAggregate { * Note: Geopackage requires that each feature table has exactly one geometry column, * while SQLStore accepts any number of geometry columns (including zero). */ - throw new IncompatibleResourceException("Unsupported resource type"); + throw new IncompatibleResourceException("Unsupported resource type").addAspect("class"); } /**