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]