This is an automated email from the ASF dual-hosted git repository.
afs pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 7a42f6b17c GH-4275: Reject non-finite GeoSPARQL transformation results
7a42f6b17c is described below
commit 7a42f6b17cc31cc86c13462d53485274e6529da6
Author: Edmond Chuc <[email protected]>
AuthorDate: Wed Sep 30 19:43:12 2026 +1000
GH-4275: Reject non-finite GeoSPARQL transformation results
Reject non-finite transformed X/Y and consumed transformed Z with
TransformException before BigDecimal precision cleanup can throw
NumberFormatException.
Preserve existing precision rounding and source Z/M handling, including
ignoring unused target dimensions from 2D transformations.
Cover NaN and both infinities across X/Y/Z, finite 2D and 3D Z/M
semantics, and a 2D-to-3D transform with unused NaN output.
---
.../implementation/jts/GeometryTransformation.java | 13 +++--
.../implementation/jts/GeometryTransformTest.java | 59 ++++++++++++++++++++++
2 files changed, 69 insertions(+), 3 deletions(-)
diff --git
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformation.java
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformation.java
index 7ffaa419ff..bb7ae09830 100644
---
a/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformation.java
+++
b/jena-geosparql/src/main/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformation.java
@@ -211,10 +211,10 @@ public class GeometryTransformation {
for (int i = 0; i < size; i++) {
Coordinate coord = coordSeq.getCoordinate(i);
int j = i * targetDims;
- x[i] = cleanUpPrecision(targetPts[j]);
- y[i] = cleanUpPrecision(targetPts[j + 1]);
+ x[i] = cleanUpTransformedOrdinate(targetPts[j]);
+ y[i] = cleanUpTransformedOrdinate(targetPts[j + 1]);
if (isZTransformed) {
- z[i] = cleanUpPrecision(targetPts[j + 2]);
+ z[i] = cleanUpTransformedOrdinate(targetPts[j + 2]);
} else {
if (coordSeq.hasZ()) {
z[i] = cleanUpPrecision(coord.getZ());
@@ -233,4 +233,11 @@ public class GeometryTransformation {
return new CustomCoordinateSequence(x, y, z, m);
}
+ private static double cleanUpTransformedOrdinate(double ordinate) throws
TransformException {
+ if (!Double.isFinite(ordinate)) {
+ throw new TransformException("Non-finite transformed ordinate: " +
ordinate);
+ }
+ return cleanUpPrecision(ordinate);
+ }
+
}
diff --git
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformTest.java
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformTest.java
index cd111d2f49..c45c8d3485 100644
---
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformTest.java
+++
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/jts/GeometryTransformTest.java
@@ -25,13 +25,17 @@ import
org.apache.jena.geosparql.implementation.parsers.wkt.WKTReader;
import org.apache.jena.geosparql.implementation.registry.MathTransformRegistry;
import org.apache.jena.geosparql.implementation.vocabulary.SRS_URI;
import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Coordinate;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
@@ -109,5 +113,60 @@ public class GeometryTransformTest {
assertEquals(expResult, result);
}
+ @Test
+ public void testTransformRejectsNonFiniteOrdinates() {
+ Geometry sourceGeometry = WKTReader.extract("LINESTRING Z(1 2 3, 4 5
6)").getGeometry();
+ for (double value : new double[] { Double.NaN,
Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }) {
+ for (int ordinate = 0; ordinate < 3; ordinate++) {
+ double[] translation = new double[3];
+ translation[ordinate] = value;
+ MathTransform transform =
MathTransforms.translation(translation);
+ assertThrows("Ordinate " + ordinate + ": " + value,
TransformException.class,
+ () -> GeometryTransformation.transform(sourceGeometry,
transform));
+ }
+ }
+ }
+
+ @Test
+ public void testTransform2DPreservesZM() throws TransformException {
+ Geometry sourceGeometry = WKTReader.extract("POINT ZM(1 2 3
4)").getGeometry();
+ Geometry result = GeometryTransformation.transform(sourceGeometry,
MathTransforms.translation(10, 20));
+ Coordinate coordinate = result.getCoordinate();
+ assertEquals(11, coordinate.getX(), 0);
+ assertEquals(22, coordinate.getY(), 0);
+ assertEquals(3, coordinate.getZ(), 0);
+ assertEquals(4, coordinate.getM(), 0);
+ }
+
+ @Test
+ public void testTransform3DPreservesM() throws TransformException {
+ Geometry sourceGeometry = WKTReader.extract("POINT ZM(1 2 3
4)").getGeometry();
+ Geometry result = GeometryTransformation.transform(sourceGeometry,
MathTransforms.translation(10, 20, 30));
+ Coordinate coordinate = result.getCoordinate();
+ assertEquals(11, coordinate.getX(), 0);
+ assertEquals(22, coordinate.getY(), 0);
+ assertEquals(33, coordinate.getZ(), 0);
+ assertEquals(4, coordinate.getM(), 0);
+ }
+
+ @Test
+ public void testTransform2DTo3DIgnoresUnusedNaNAndPreservesZM() throws
TransformException {
+ Geometry sourceGeometry = WKTReader.extract("POINT ZM(1 2 3
4)").getGeometry();
+ MathTransform transform = MathTransforms.linear(Matrices.create(4, 3,
new double[] {
+ 1, 0, 10,
+ 0, 1, 20,
+ 0, 0, Double.NaN,
+ 0, 0, 1
+ }));
+ assertEquals(2, transform.getSourceDimensions());
+ assertEquals(3, transform.getTargetDimensions());
+ Geometry result = GeometryTransformation.transform(sourceGeometry,
transform);
+ Coordinate coordinate = result.getCoordinate();
+ assertEquals(11, coordinate.getX(), 0);
+ assertEquals(22, coordinate.getY(), 0);
+ assertEquals(3, coordinate.getZ(), 0);
+ assertEquals(4, coordinate.getM(), 0);
+ }
+
//TODO - additional tests
}