This is an automated email from the ASF dual-hosted git repository.
chl-wxp pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git
The following commit(s) were added to refs/heads/dev by this push:
new 0e2f4ef8d5 [Fix][API] Add missing OptionRule validation for
CatalogFactory creation path (#11127)
0e2f4ef8d5 is described below
commit 0e2f4ef8d57000df40bfc2a3f32c635fe632b6c0
Author: zhiwei.niu <[email protected]>
AuthorDate: Mon Jun 22 10:25:40 2026 +0800
[Fix][API] Add missing OptionRule validation for CatalogFactory creation
path (#11127)
---
.../seatunnel/api/table/factory/FactoryUtil.java | 8 ++-
.../api/table/catalog/CatalogTableUtilTest.java | 66 ++++++++++++++++++++++
.../jdbc/catalog/duckdb/DuckDBCatalogFactory.java | 12 +++-
.../lance/catalog/LanceCatalogFactory.java | 2 +-
4 files changed, 84 insertions(+), 4 deletions(-)
diff --git
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java
index 8412bc60ce..a4f078db0c 100644
---
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java
+++
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java
@@ -286,13 +286,17 @@ public final class FactoryUtil {
public static Optional<Catalog> createOptionalCatalog(
String catalogName,
- ReadonlyConfig options,
+ ReadonlyConfig readonlyConfig,
ClassLoader classLoader,
String factoryIdentifier) {
Optional<CatalogFactory> optionalFactory =
discoverOptionalFactory(classLoader, CatalogFactory.class,
factoryIdentifier);
+
return optionalFactory.map(
- catalogFactory -> catalogFactory.createCatalog(catalogName,
options));
+ catalogFactory -> {
+
ConfigValidator.of(readonlyConfig).validate(catalogFactory.optionRule());
+ return catalogFactory.createCatalog(catalogName,
readonlyConfig);
+ });
}
public static <T extends Factory> URL getFactoryUrl(T factory) {
diff --git
a/seatunnel-api/src/test/java/org/apache/seatunnel/api/table/catalog/CatalogTableUtilTest.java
b/seatunnel-api/src/test/java/org/apache/seatunnel/api/table/catalog/CatalogTableUtilTest.java
index 73a6b3d47d..e9cd815f27 100644
---
a/seatunnel-api/src/test/java/org/apache/seatunnel/api/table/catalog/CatalogTableUtilTest.java
+++
b/seatunnel-api/src/test/java/org/apache/seatunnel/api/table/catalog/CatalogTableUtilTest.java
@@ -22,7 +22,9 @@ import
org.apache.seatunnel.shade.com.typesafe.config.ConfigFactory;
import org.apache.seatunnel.shade.com.typesafe.config.ConfigValueFactory;
import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.OptionValidationException;
import org.apache.seatunnel.api.options.ConnectorCommonOptions;
+import org.apache.seatunnel.api.table.factory.FactoryUtil;
import org.apache.seatunnel.api.table.type.ArrayType;
import org.apache.seatunnel.api.table.type.BasicType;
import org.apache.seatunnel.api.table.type.DecimalType;
@@ -43,7 +45,10 @@ import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import static
org.apache.seatunnel.common.constants.CollectionConstants.PLUGIN_NAME;
@@ -208,4 +213,65 @@ public class CatalogTableUtilTest {
}
return Paths.get(resource.toURI()).toString();
}
+
+ @Test
+ void createOptionalCatalogWithValidConfig() {
+ Map<String, Object> configMap = new HashMap<>();
+ configMap.put("username", "admin");
+ configMap.put("password", "secret");
+ ReadonlyConfig config = ReadonlyConfig.fromMap(configMap);
+
+ Optional<Catalog> catalog =
+ FactoryUtil.createOptionalCatalog(
+ "test", config,
Thread.currentThread().getContextClassLoader(), "InMemory");
+
+ Assertions.assertTrue(catalog.isPresent());
+ }
+
+ @Test
+ void createOptionalCatalogWithMissingRequiredOptionsThrows() {
+ Map<String, Object> configMap = new HashMap<>();
+ configMap.put("host", "localhost");
+ ReadonlyConfig config = ReadonlyConfig.fromMap(configMap);
+
+ Assertions.assertThrows(
+ OptionValidationException.class,
+ () ->
+ FactoryUtil.createOptionalCatalog(
+ "test",
+ config,
+ Thread.currentThread().getContextClassLoader(),
+ "InMemory"));
+ }
+
+ @Test
+ void createOptionalCatalogWithPartialRequiredOptionsThrows() {
+ Map<String, Object> configMap = new HashMap<>();
+ configMap.put("username", "admin");
+ ReadonlyConfig config = ReadonlyConfig.fromMap(configMap);
+
+ Assertions.assertThrows(
+ OptionValidationException.class,
+ () ->
+ FactoryUtil.createOptionalCatalog(
+ "test",
+ config,
+ Thread.currentThread().getContextClassLoader(),
+ "InMemory"));
+ }
+
+ @Test
+ void createOptionalCatalogWithUnknownFactoryReturnsEmpty() {
+ Map<String, Object> configMap = new HashMap<>();
+ ReadonlyConfig config = ReadonlyConfig.fromMap(configMap);
+
+ Optional<Catalog> catalog =
+ FactoryUtil.createOptionalCatalog(
+ "test",
+ config,
+ Thread.currentThread().getContextClassLoader(),
+ "NonExistentFactory");
+
+ Assertions.assertFalse(catalog.isPresent());
+ }
}
diff --git
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/duckdb/DuckDBCatalogFactory.java
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/duckdb/DuckDBCatalogFactory.java
index 1e966111e7..53999ace8f 100644
---
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/duckdb/DuckDBCatalogFactory.java
+++
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/catalog/duckdb/DuckDBCatalogFactory.java
@@ -28,6 +28,13 @@ import
org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.DatabaseI
import com.google.auto.service.AutoService;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.DECIMAL_TYPE_NARROWING;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.HANDLE_BLOB_AS_STRING;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.PASSWORD;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.SCHEMA;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.URL;
+import static
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions.USERNAME;
+
/** Factory for {@link DuckDBCatalog} */
@AutoService(Factory.class)
public class DuckDBCatalogFactory implements CatalogFactory {
@@ -50,6 +57,9 @@ public class DuckDBCatalogFactory implements CatalogFactory {
@Override
public OptionRule optionRule() {
- return JdbcCommonOptions.BASE_CATALOG_RULE.build();
+ return OptionRule.builder()
+ .required(URL)
+ .optional(USERNAME, PASSWORD, SCHEMA, DECIMAL_TYPE_NARROWING,
HANDLE_BLOB_AS_STRING)
+ .build();
}
}
diff --git
a/seatunnel-connectors-v2/connector-lance/src/main/java/org/apache/seatunnel/connectors/seatunnel/lance/catalog/LanceCatalogFactory.java
b/seatunnel-connectors-v2/connector-lance/src/main/java/org/apache/seatunnel/connectors/seatunnel/lance/catalog/LanceCatalogFactory.java
index 4235a141a4..7d26b4e8ef 100644
---
a/seatunnel-connectors-v2/connector-lance/src/main/java/org/apache/seatunnel/connectors/seatunnel/lance/catalog/LanceCatalogFactory.java
+++
b/seatunnel-connectors-v2/connector-lance/src/main/java/org/apache/seatunnel/connectors/seatunnel/lance/catalog/LanceCatalogFactory.java
@@ -35,6 +35,6 @@ public class LanceCatalogFactory implements CatalogFactory {
@Override
public OptionRule optionRule() {
- return null;
+ return OptionRule.builder().build();
}
}