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

wenchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 76d4718d2258 [SPARK-53920][GEO][SQL] Introduce GeometryType and 
GeographyType to Java API
76d4718d2258 is described below

commit 76d4718d2258b34aef28743f10d80a9898bd9223
Author: Uros Bojanic <[email protected]>
AuthorDate: Thu Oct 23 21:37:00 2025 +0800

    [SPARK-53920][GEO][SQL] Introduce GeometryType and GeographyType to Java API
    
    ### What changes were proposed in this pull request?
    Introduce two new geospatial data types to Java API:
    - `GeographyType`
    - `GeometryType`
    
    Note that the GEOMETRY and GEOGRAPHY logical types were recently included 
to Spark SQL as part of: https://github.com/apache/spark/pull/52491.
    
    ### Why are the changes needed?
    Expanding on GEOMETRY and GEOGRAPHY type support across all of the 
supported APIs.
    
    ### Does this PR introduce _any_ user-facing change?
    Yes, two new data types are now available to users of the Java API.
    
    ### How was this patch tested?
    Added new tests to:
    - `JavaGeographyTypeSuite`
    - `JavaGeometryTypeSuite`
    
    ### Was this patch authored or co-authored using generative AI tooling?
    No.
    
    Closes #52623 from uros-db/geo-java-types.
    
    Authored-by: Uros Bojanic <[email protected]>
    Signed-off-by: Wenchen Fan <[email protected]>
---
 .../java/org/apache/spark/sql/types/DataTypes.java | 36 ++++++++
 .../spark/sql/types/JavaGeographyTypeSuite.java    | 97 +++++++++++++++++++++
 .../spark/sql/types/JavaGeometryTypeSuite.java     | 98 ++++++++++++++++++++++
 3 files changed, 231 insertions(+)

diff --git a/sql/api/src/main/java/org/apache/spark/sql/types/DataTypes.java 
b/sql/api/src/main/java/org/apache/spark/sql/types/DataTypes.java
index 0034b8e71518..a32a27602f0a 100644
--- a/sql/api/src/main/java/org/apache/spark/sql/types/DataTypes.java
+++ b/sql/api/src/main/java/org/apache/spark/sql/types/DataTypes.java
@@ -94,6 +94,42 @@ public class DataTypes {
    */
   public static final DataType ShortType = ShortType$.MODULE$;
 
+  /**
+   * Creates a GeographyType by specifying the SRID value.
+   *
+   * @since 4.1.0
+   */
+  public static GeographyType createGeographyType(int srid) {
+    return GeographyType$.MODULE$.apply(srid);
+  }
+
+  /**
+   * Creates a GeographyType by specifying the CRS value.
+   *
+   * @since 4.1.0
+   */
+  public static GeographyType createGeographyType(String crs) {
+    return GeographyType$.MODULE$.apply(crs);
+  }
+
+  /**
+   * Creates a GeometryType by specifying the SRID value.
+   *
+   * @since 4.1.0
+   */
+  public static GeometryType createGeometryType(int srid) {
+    return GeometryType$.MODULE$.apply(srid);
+  }
+
+  /**
+   * Creates a GeometryType by specifying the CRS value.
+   *
+   * @since 4.1.0
+   */
+  public static GeometryType createGeometryType(String crs) {
+    return GeometryType$.MODULE$.apply(crs);
+  }
+
   /**
    * Gets the NullType object.
    */
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeographyTypeSuite.java
 
b/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeographyTypeSuite.java
new file mode 100644
index 000000000000..39ecd3893c7f
--- /dev/null
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeographyTypeSuite.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.types;
+
+import org.apache.spark.sql.internal.types.SpatialReferenceSystemMapper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.apache.spark.SparkIllegalArgumentException;
+
+import java.util.stream.Stream;
+
+public class JavaGeographyTypeSuite {
+
+  /*
+   * Test cases GeographyType construction based on SRID.
+   */
+
+  @Test
+  public void geographyTypeWithSpecifiedValidSridTest() {
+    // Valid SRID values for GEOGRAPHY. Note that only 4326 is supported for 
now.
+    Stream.of(4326).forEach(srid -> {
+      DataType geographyType = DataTypes.createGeographyType(srid);
+      Assertions.assertEquals("GEOGRAPHY(" + srid + ")", geographyType.sql());
+      Assertions.assertEquals("geography(" + srid + ")", 
geographyType.typeName());
+      Assertions.assertEquals("geography(" + srid + ")", 
geographyType.simpleString());
+    });
+  }
+
+  @Test
+  public void geographyTypeWithSpecifiedInvalidSridTest() {
+    // Invalid SRID values for GEOGRAPHY.
+    Stream.of(-1, -2, 0, 1, 2).forEach(srid -> {
+      try {
+        DataTypes.createGeographyType(srid);
+        Assertions.fail("Expected SparkIllegalArgumentException for SRID: " + 
srid);
+      } catch (SparkIllegalArgumentException e) {
+        Assertions.assertEquals("ST_INVALID_SRID_VALUE", e.getCondition());
+        Assertions.assertEquals(String.valueOf(srid), 
e.getMessageParameters().get("srid"));
+      }
+    });
+  }
+
+  /*
+   * Test cases GeographyType construction based on CRS.
+   */
+
+  @Test
+  public void geographyTypeWithSpecifiedValidCrsTest() {
+    // Valid CRS values for GEOGRAPHY. Note that only 4326 is supported for 
now.
+    int srid = GeographyType.GEOGRAPHY_DEFAULT_SRID();
+    Stream.of("OGC:CRS84", "EPSG:4326").forEach(crs -> {
+      DataType geographyType = DataTypes.createGeographyType(crs);
+      Assertions.assertEquals("GEOGRAPHY(" + srid + ")", geographyType.sql());
+      Assertions.assertEquals("geography(" + srid + ")", 
geographyType.typeName());
+      Assertions.assertEquals("geography(" + srid + ")", 
geographyType.simpleString());
+    });
+  }
+
+  @Test
+  public void geographyTypeWithSpecifiedInvalidCrsTest() {
+    // Invalid CRS values for GEOGRAPHY.
+    Stream.of("0", "SRID", "SRID:-1", "SRID:4326", "CRS84", "").forEach(crs -> 
{
+      try {
+        DataTypes.createGeographyType(crs);
+        Assertions.fail("Expected SparkIllegalArgumentException for CRS: " + 
crs);
+      } catch (SparkIllegalArgumentException e) {
+        Assertions.assertEquals("ST_INVALID_CRS_VALUE", e.getCondition());
+        Assertions.assertEquals(crs, e.getMessageParameters().get("crs"));
+      }
+    });
+  }
+
+  @Test
+  public void geographyTypeWithSpecifiedAnyTest() {
+    // Special string value "ANY" in place of CRS is used to denote a mixed 
GEOGRAPHY type.
+    DataType geographyType = DataTypes.createGeographyType("ANY");
+    Assertions.assertEquals("GEOGRAPHY(ANY)", geographyType.sql());
+    Assertions.assertEquals("geography(any)", geographyType.typeName());
+    Assertions.assertEquals("geography(any)", geographyType.simpleString());
+  }
+}
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeometryTypeSuite.java 
b/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeometryTypeSuite.java
new file mode 100644
index 000000000000..03485feeb3f9
--- /dev/null
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/types/JavaGeometryTypeSuite.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.types;
+
+import org.apache.spark.sql.internal.types.SpatialReferenceSystemMapper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.apache.spark.SparkIllegalArgumentException;
+
+import java.util.stream.Stream;
+
+public class JavaGeometryTypeSuite {
+
+  /*
+   * Test cases GeometryType construction based on SRID.
+   */
+
+  @Test
+  public void geometryTypeWithSpecifiedValidSridTest() {
+    // Valid SRID values for GEOMETRY.
+    Stream.of(0, 3857, 4326).forEach(srid -> {
+      DataType geometryType = DataTypes.createGeometryType(srid);
+      Assertions.assertEquals("GEOMETRY(" + srid + ")", geometryType.sql());
+      Assertions.assertEquals("geometry(" + srid + ")", 
geometryType.typeName());
+      Assertions.assertEquals("geometry(" + srid + ")", 
geometryType.simpleString());
+    });
+  }
+
+  @Test
+  public void geometryTypeWithSpecifiedInvalidSridTest() {
+    // Invalid SRID values for GEOMETRY.
+    Stream.of(-1, -2, 1, 2).forEach(srid -> {
+      try {
+        DataTypes.createGeometryType(srid);
+        Assertions.fail("Expected SparkIllegalArgumentException for SRID: " + 
srid);
+      } catch (SparkIllegalArgumentException e) {
+        Assertions.assertEquals("ST_INVALID_SRID_VALUE", e.getCondition());
+        Assertions.assertEquals(String.valueOf(srid), 
e.getMessageParameters().get("srid"));
+      }
+    });
+  }
+
+  /*
+   * Test cases GeometryType construction based on CRS.
+   */
+
+  @Test
+  public void geometryTypeWithSpecifiedValidCrsTest() {
+    // Valid CRS values for GEOMETRY.
+    SpatialReferenceSystemMapper srsMapper = 
SpatialReferenceSystemMapper.get();
+    Stream.of("SRID:0", "EPSG:3857", "OGC:CRS84").forEach(crs -> {
+      int srid = srsMapper.getSrid(crs);
+      DataType geometryType = DataTypes.createGeometryType(crs);
+      Assertions.assertEquals("GEOMETRY(" + srid + ")", geometryType.sql());
+      Assertions.assertEquals("geometry(" + srid + ")", 
geometryType.typeName());
+      Assertions.assertEquals("geometry(" + srid + ")", 
geometryType.simpleString());
+    });
+  }
+
+  @Test
+  public void geometryTypeWithSpecifiedInvalidCrsTest() {
+    // Invalid CRS values for GEOMETRY.
+    Stream.of("0", "SRID", "SRID:-1", "SRID:4326", "CRS84", "").forEach(crs -> 
{
+      try {
+        DataTypes.createGeometryType(crs);
+        Assertions.fail("Expected SparkIllegalArgumentException for CRS: " + 
crs);
+      } catch (SparkIllegalArgumentException e) {
+        Assertions.assertEquals("ST_INVALID_CRS_VALUE", e.getCondition());
+        Assertions.assertEquals(crs, e.getMessageParameters().get("crs"));
+      }
+    });
+  }
+
+  @Test
+  public void geometryTypeWithSpecifiedAnyTest() {
+    // Special string value "ANY" in place of CRS is used to denote a mixed 
GEOMETRY type.
+    DataType geometryType = DataTypes.createGeometryType("ANY");
+    Assertions.assertEquals("GEOMETRY(ANY)", geometryType.sql());
+    Assertions.assertEquals("geometry(any)", geometryType.typeName());
+    Assertions.assertEquals("geometry(any)", geometryType.simpleString());
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to