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
 }

Reply via email to