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

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


The following commit(s) were added to refs/heads/master by this push:
     new 49d060c818c Validate algorithm types at configuration entry points 
(#40075)
49d060c818c is described below

commit 49d060c818c99a420ba22564031d63cf52a79709
Author: Liang Zhang <[email protected]>
AuthorDate: Tue Oct 6 16:37:42 2026 +0800

    Validate algorithm types at configuration entry points (#40075)
---
 .../encrypt/config/EncryptRuleConfiguration.java   |   3 +-
 .../config/EncryptRuleConfigurationTest.java       |  15 +
 .../mask/config/MaskRuleConfiguration.java         |   3 +-
 .../mask/config/MaskRuleConfigurationTest.java     |  15 +
 .../ReadwriteSplittingRuleConfiguration.java       |   3 +-
 .../ReadwriteSplittingRuleConfigurationTest.java   |  16 +
 .../shadow/config/ShadowRuleConfiguration.java     |   3 +-
 .../shadow/config/ShadowRuleConfigurationTest.java |  18 ++
 .../api/config/ShardingRuleConfiguration.java      |   9 +-
 .../api/config/ShardingRuleConfigurationTest.java  |  29 ++
 infra/algorithm/core/pom.xml                       |   4 +
 .../core/config/AlgorithmConfiguration.java        |   5 +-
 .../core/config/AlgorithmConfigurationTest.java    |  20 +-
 .../reachability-metadata.json                     | 324 +++++++++++++++++++++
 .../config/AuthorityRuleConfiguration.java         |   5 +-
 .../config/AuthorityRuleConfigurationTest.java     |  26 ++
 .../config/PipelineProcessConfiguration.java       |   5 +
 .../progress/config/PipelineReadConfiguration.java |   3 +
 .../config/PipelineWriteConfiguration.java         |   3 +
 ...PipelineProcessConfigurationPersistService.java |  24 +-
 20 files changed, 516 insertions(+), 17 deletions(-)

diff --git 
a/features/encrypt/api/src/main/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfiguration.java
 
b/features/encrypt/api/src/main/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfiguration.java
index af880959b8e..32aa90569c3 100644
--- 
a/features/encrypt/api/src/main/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfiguration.java
+++ 
b/features/encrypt/api/src/main/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfiguration.java
@@ -51,7 +51,8 @@ public final class EncryptRuleConfiguration implements 
DatabaseRuleConfiguration
     private final Collection<@NotNull EncryptTableRuleConfiguration> tables;
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm", groups = 
RuleConfigurationTypeValidationGroup.class)
     private final Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
encryptors;
     
     @Override
diff --git 
a/features/encrypt/api/src/test/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfigurationTest.java
 
b/features/encrypt/api/src/test/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfigurationTest.java
index e295c92d717..2d641e0811a 100644
--- 
a/features/encrypt/api/src/test/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfigurationTest.java
+++ 
b/features/encrypt/api/src/test/java/org/apache/shardingsphere/encrypt/config/EncryptRuleConfigurationTest.java
@@ -90,6 +90,21 @@ class EncryptRuleConfigurationTest {
         return createRuleConfiguration(Arrays.asList(fooColumnConfig, 
barColumnConfig), Collections.singletonMap("foo_encryptor", new 
AlgorithmConfiguration("FIXTURE", new Properties())));
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final String type, 
final String expectedMessage) {
+        EncryptRuleConfiguration ruleConfig = new 
EncryptRuleConfiguration(Collections.emptyList(), 
Collections.singletonMap("foo_encryptor", new AlgorithmConfiguration(type, new 
Properties())));
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 'EncryptRuleConfiguration' 
rule, error message is: " + expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        return Stream.of(
+                Arguments.of("Null encryptor type before SPI", null, "Property 
`encryptors[foo_encryptor].type` Type is required."),
+                Arguments.of("Empty encryptor type before SPI", "", "Property 
`encryptors[foo_encryptor].type` Type is required."),
+                Arguments.of("Whitespace encryptor type reaches SPI", " ", 
"Property `encryptors` does not match an available SPI implementation."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
     void assertValidateInvalidRuleConfiguration(final String name, final 
EncryptRuleConfiguration ruleConfig) {
diff --git 
a/features/mask/api/src/main/java/org/apache/shardingsphere/mask/config/MaskRuleConfiguration.java
 
b/features/mask/api/src/main/java/org/apache/shardingsphere/mask/config/MaskRuleConfiguration.java
index e58e4cff502..f4c4660e2c5 100644
--- 
a/features/mask/api/src/main/java/org/apache/shardingsphere/mask/config/MaskRuleConfiguration.java
+++ 
b/features/mask/api/src/main/java/org/apache/shardingsphere/mask/config/MaskRuleConfiguration.java
@@ -50,7 +50,8 @@ public final class MaskRuleConfiguration implements 
DatabaseRuleConfiguration, E
     private final Collection<@NotNull MaskTableRuleConfiguration> tables;
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.mask.spi.MaskAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.mask.spi.MaskAlgorithm", groups = 
RuleConfigurationTypeValidationGroup.class)
     private final Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
maskAlgorithms;
     
     @Override
diff --git 
a/features/mask/api/src/test/java/org/apache/shardingsphere/mask/config/MaskRuleConfigurationTest.java
 
b/features/mask/api/src/test/java/org/apache/shardingsphere/mask/config/MaskRuleConfigurationTest.java
index 9b83e3c8e5a..7ab22f97410 100644
--- 
a/features/mask/api/src/test/java/org/apache/shardingsphere/mask/config/MaskRuleConfigurationTest.java
+++ 
b/features/mask/api/src/test/java/org/apache/shardingsphere/mask/config/MaskRuleConfigurationTest.java
@@ -73,6 +73,21 @@ class MaskRuleConfigurationTest {
                         Collections.singletonMap("foo_mask", new 
AlgorithmConfiguration("FIXTURE", new Properties())))));
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final String type, 
final String expectedMessage) {
+        MaskRuleConfiguration ruleConfig = new 
MaskRuleConfiguration(Collections.emptyList(), 
Collections.singletonMap("foo_mask", new AlgorithmConfiguration(type, new 
Properties())));
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 'MaskRuleConfiguration' 
rule, error message is: " + expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        return Stream.of(
+                Arguments.of("Null mask algorithm type before SPI", null, 
"Property `maskAlgorithms[foo_mask].type` Type is required."),
+                Arguments.of("Empty mask algorithm type before SPI", "", 
"Property `maskAlgorithms[foo_mask].type` Type is required."),
+                Arguments.of("Whitespace mask algorithm type reaches SPI", " 
", "Property `maskAlgorithms` does not match an available SPI 
implementation."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
     void assertValidateInvalidRuleConfiguration(final String name, final 
MaskRuleConfiguration ruleConfig) {
diff --git 
a/features/readwrite-splitting/api/src/main/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfiguration.java
 
b/features/readwrite-splitting/api/src/main/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfiguration.java
index 1dd16925812..701b4f5229a 100644
--- 
a/features/readwrite-splitting/api/src/main/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfiguration.java
+++ 
b/features/readwrite-splitting/api/src/main/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfiguration.java
@@ -46,6 +46,7 @@ public final class ReadwriteSplittingRuleConfiguration 
implements DatabaseRuleCo
     private final Collection<@NotNull 
ReadwriteSplittingDataSourceGroupRuleConfiguration> dataSourceGroups;
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.infra.algorithm.loadbalancer.spi.LoadBalanceAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.infra.algorithm.loadbalancer.spi.LoadBalanceAlgorithm",
 groups = RuleConfigurationTypeValidationGroup.class)
     private final Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
loadBalancers;
 }
diff --git 
a/features/readwrite-splitting/api/src/test/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfigurationTest.java
 
b/features/readwrite-splitting/api/src/test/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfigurationTest.java
index 8060ea9983c..feb67831433 100644
--- 
a/features/readwrite-splitting/api/src/test/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfigurationTest.java
+++ 
b/features/readwrite-splitting/api/src/test/java/org/apache/shardingsphere/readwritesplitting/config/ReadwriteSplittingRuleConfigurationTest.java
@@ -60,6 +60,22 @@ class ReadwriteSplittingRuleConfigurationTest {
                         Collections.singletonMap("foo_load_balancer", new 
AlgorithmConfiguration("FIXTURE", new Properties())))));
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final String type, 
final String expectedMessage) {
+        ReadwriteSplittingRuleConfiguration ruleConfig = new 
ReadwriteSplittingRuleConfiguration(Collections.emptyList(),
+                Collections.singletonMap("foo_load_balancer", new 
AlgorithmConfiguration(type, new Properties())));
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 
'ReadwriteSplittingRuleConfiguration' rule, error message is: " + 
expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        return Stream.of(
+                Arguments.of("Null load balancer type before SPI", null, 
"Property `loadBalancers[foo_load_balancer].type` Type is required."),
+                Arguments.of("Empty load balancer type before SPI", "", 
"Property `loadBalancers[foo_load_balancer].type` Type is required."),
+                Arguments.of("Whitespace load balancer type reaches SPI", " ", 
"Property `loadBalancers` does not match an available SPI implementation."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
     void assertValidateInvalidRuleConfiguration(final String name, final 
ReadwriteSplittingRuleConfiguration ruleConfig) {
diff --git 
a/features/shadow/api/src/main/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfiguration.java
 
b/features/shadow/api/src/main/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfiguration.java
index fa04928d73b..4a51c67affd 100644
--- 
a/features/shadow/api/src/main/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfiguration.java
+++ 
b/features/shadow/api/src/main/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfiguration.java
@@ -53,7 +53,8 @@ public final class ShadowRuleConfiguration implements 
DatabaseRuleConfiguration,
     private Map<@NotBlank String, @NotNull ShadowTableConfiguration> tables = 
new LinkedHashMap<>();
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.shadow.spi.ShadowAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.shadow.spi.ShadowAlgorithm", groups = 
RuleConfigurationTypeValidationGroup.class)
     private Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
shadowAlgorithms = new LinkedHashMap<>();
     
     private String defaultShadowAlgorithmName;
diff --git 
a/features/shadow/api/src/test/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfigurationTest.java
 
b/features/shadow/api/src/test/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfigurationTest.java
index bbb051c6b8d..1fedec45649 100644
--- 
a/features/shadow/api/src/test/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfigurationTest.java
+++ 
b/features/shadow/api/src/test/java/org/apache/shardingsphere/shadow/config/ShadowRuleConfigurationTest.java
@@ -32,6 +32,8 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.stream.Stream;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -71,6 +73,22 @@ class ShadowRuleConfigurationTest {
         return result;
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final String type, 
final String expectedMessage) {
+        ShadowRuleConfiguration ruleConfig = 
createRuleConfiguration(Collections.emptyList(), Collections.emptyMap(),
+                Collections.singletonMap("foo_shadow_algorithm", new 
AlgorithmConfiguration(type, new Properties())));
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 'ShadowRuleConfiguration' 
rule, error message is: " + expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        return Stream.of(
+                Arguments.of("Null shadow algorithm type before SPI", null, 
"Property `shadowAlgorithms[foo_shadow_algorithm].type` Type is required."),
+                Arguments.of("Empty shadow algorithm type before SPI", "", 
"Property `shadowAlgorithms[foo_shadow_algorithm].type` Type is required."),
+                Arguments.of("Whitespace shadow algorithm type reaches SPI", " 
", "Property `shadowAlgorithms` does not match an available SPI 
implementation."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
     void assertValidateInvalidRuleConfiguration(final String name, final 
ShadowRuleConfiguration ruleConfig) {
diff --git 
a/features/sharding/api/src/main/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfiguration.java
 
b/features/sharding/api/src/main/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfiguration.java
index 0ff03c9855f..303c5466d74 100644
--- 
a/features/sharding/api/src/main/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfiguration.java
+++ 
b/features/sharding/api/src/main/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfiguration.java
@@ -81,15 +81,18 @@ public final class ShardingRuleConfiguration implements 
DatabaseRuleConfiguratio
     private Map<@NotBlank String, @NotNull KeyGenerateStrategiesConfiguration> 
keyGenerateStrategies = new LinkedHashMap<>();
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.sharding.spi.ShardingAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.sharding.spi.ShardingAlgorithm", groups = 
RuleConfigurationTypeValidationGroup.class)
     private Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
shardingAlgorithms = new LinkedHashMap<>();
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.infra.algorithm.keygen.spi.KeyGenerateAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.infra.algorithm.keygen.spi.KeyGenerateAlgorithm", 
groups = RuleConfigurationTypeValidationGroup.class)
     private Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
keyGenerators = new LinkedHashMap<>();
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm", groups = 
RuleConfigurationTypeValidationGroup.class)
     private Map<@NotBlank String, @NotNull AlgorithmConfiguration> auditors = 
new LinkedHashMap<>();
     
     @Override
diff --git 
a/features/sharding/api/src/test/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfigurationTest.java
 
b/features/sharding/api/src/test/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfigurationTest.java
index 8cb9a7a8404..dd5584f09f9 100644
--- 
a/features/sharding/api/src/test/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfigurationTest.java
+++ 
b/features/sharding/api/src/test/java/org/apache/shardingsphere/sharding/api/config/ShardingRuleConfigurationTest.java
@@ -301,6 +301,35 @@ class ShardingRuleConfigurationTest {
                         new 
SequenceKeyGenerateStrategiesRuleConfiguration("foo_key_generator", ""))));
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final 
ShardingRuleConfiguration ruleConfig, final String expectedMessage) {
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 
'ShardingRuleConfiguration' rule, error message is: " + expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        return Stream.of(
+                Arguments.of("Null sharding algorithm type before SPI", 
createShardingAlgorithmsRuleConfiguration("foo_sharding", new 
AlgorithmConfiguration(null, new Properties())),
+                        "Property `shardingAlgorithms[foo_sharding].type` Type 
is required."),
+                Arguments.of("Empty sharding algorithm type before SPI", 
createShardingAlgorithmsRuleConfiguration("foo_sharding", new 
AlgorithmConfiguration("", new Properties())),
+                        "Property `shardingAlgorithms[foo_sharding].type` Type 
is required."),
+                Arguments.of("Whitespace sharding algorithm type reaches SPI", 
createShardingAlgorithmsRuleConfiguration("foo_sharding", new 
AlgorithmConfiguration(" ", new Properties())),
+                        "Property `shardingAlgorithms` does not match an 
available SPI implementation."),
+                Arguments.of("Null key generator type before SPI", 
createKeyGeneratorsRuleConfiguration("foo_key_generator", new 
AlgorithmConfiguration(null, new Properties())),
+                        "Property `keyGenerators[foo_key_generator].type` Type 
is required."),
+                Arguments.of("Empty key generator type before SPI", 
createKeyGeneratorsRuleConfiguration("foo_key_generator", new 
AlgorithmConfiguration("", new Properties())),
+                        "Property `keyGenerators[foo_key_generator].type` Type 
is required."),
+                Arguments.of("Whitespace key generator type reaches SPI", 
createKeyGeneratorsRuleConfiguration("foo_key_generator", new 
AlgorithmConfiguration(" ", new Properties())),
+                        "Property `keyGenerators` does not match an available 
SPI implementation."),
+                Arguments.of("Null auditor type before SPI", 
createAuditorsRuleConfiguration("foo_auditor", new AlgorithmConfiguration(null, 
new Properties())),
+                        "Property `auditors[foo_auditor].type` Type is 
required."),
+                Arguments.of("Empty auditor type before SPI", 
createAuditorsRuleConfiguration("foo_auditor", new AlgorithmConfiguration("", 
new Properties())),
+                        "Property `auditors[foo_auditor].type` Type is 
required."),
+                Arguments.of("Whitespace auditor type reaches SPI", 
createAuditorsRuleConfiguration("foo_auditor", new AlgorithmConfiguration(" ", 
new Properties())),
+                        "Property `auditors` does not match an available SPI 
implementation."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidReferenceRuleConfigurationArguments")
     void assertValidateInvalidReferenceRuleConfiguration(final String name, 
final ShardingRuleConfiguration ruleConfig) {
diff --git a/infra/algorithm/core/pom.xml b/infra/algorithm/core/pom.xml
index 427321d2fab..e35bf290bc8 100644
--- a/infra/algorithm/core/pom.xml
+++ b/infra/algorithm/core/pom.xml
@@ -32,6 +32,10 @@
             <artifactId>shardingsphere-mode-spi</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>jakarta.validation</groupId>
+            <artifactId>jakarta.validation-api</artifactId>
+        </dependency>
         
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
diff --git 
a/infra/algorithm/core/src/main/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfiguration.java
 
b/infra/algorithm/core/src/main/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfiguration.java
index 333293bf53d..cf9391089c1 100644
--- 
a/infra/algorithm/core/src/main/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfiguration.java
+++ 
b/infra/algorithm/core/src/main/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfiguration.java
@@ -17,11 +17,10 @@
 
 package org.apache.shardingsphere.infra.algorithm.core.config;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 
+import javax.validation.constraints.NotEmpty;
 import java.util.Properties;
 
 /**
@@ -31,12 +30,12 @@ import java.util.Properties;
 @EqualsAndHashCode
 public final class AlgorithmConfiguration {
     
+    @NotEmpty(message = "Type is required.")
     private final String type;
     
     private final Properties props;
     
     public AlgorithmConfiguration(final String type, final Properties props) {
-        Preconditions.checkArgument(!Strings.isNullOrEmpty(type), "Type is 
required.");
         this.type = type;
         this.props = null == props ? new Properties() : props;
     }
diff --git 
a/infra/algorithm/core/src/test/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfigurationTest.java
 
b/infra/algorithm/core/src/test/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfigurationTest.java
index 9ab17192f4a..268413d6bc7 100644
--- 
a/infra/algorithm/core/src/test/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfigurationTest.java
+++ 
b/infra/algorithm/core/src/test/java/org/apache/shardingsphere/infra/algorithm/core/config/AlgorithmConfigurationTest.java
@@ -18,12 +18,17 @@
 package org.apache.shardingsphere.infra.algorithm.core.config;
 
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class AlgorithmConfigurationTest {
@@ -33,7 +38,7 @@ class AlgorithmConfigurationTest {
         Properties props = new Properties();
         AlgorithmConfiguration actual = new AlgorithmConfiguration("INLINE", 
props);
         assertThat(actual.getType(), is("INLINE"));
-        assertThat(actual.getProps(), is(props));
+        assertThat(actual.getProps(), sameInstance(props));
     }
     
     @Test
@@ -43,8 +48,13 @@ class AlgorithmConfigurationTest {
         assertTrue(actual.getProps().isEmpty());
     }
     
-    @Test
-    void assertConstructWithEmptyType() {
-        assertThat(assertThrows(IllegalArgumentException.class, () -> new 
AlgorithmConfiguration("", new Properties())).getMessage(), is("Type is 
required."));
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("provideTypes")
+    void assertConstructWithoutTypeValidation(final String name, final String 
type) {
+        assertDoesNotThrow(() -> new AlgorithmConfiguration(type, new 
Properties()));
+    }
+    
+    private static Stream<Arguments> provideTypes() {
+        return Stream.of(Arguments.of("Null type", null), Arguments.of("Empty 
type", ""), Arguments.of("Whitespace type", " "));
     }
 }
diff --git 
a/infra/reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere/infra-reachability-metadata/reachability-metadata.json
 
b/infra/reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere/infra-reachability-metadata/reachability-metadata.json
index d5982bdd347..1c4ccbca1e1 100644
--- 
a/infra/reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere/infra-reachability-metadata/reachability-metadata.json
+++ 
b/infra/reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere/infra-reachability-metadata/reachability-metadata.json
@@ -460,6 +460,211 @@
         }
       ]
     },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.constraints.NotEmptyValidator",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.constraints.NotEmptyValidatorForCharSequence",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.constraints.NotEmptyValidatorForCollection",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.constraints.NotEmptyValidatorForMap",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.ApacheValidatorFactory",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": [
+            "javax.validation.spi.ConfigurationState"
+          ]
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.ConstraintAnnotationAttributes$Types",
+      "fields": [
+        {
+          "name": "message"
+        },
+        {
+          "name": "groups"
+        },
+        {
+          "name": "payload"
+        },
+        {
+          "name": "validationAppliesTo"
+        },
+        {
+          "name": "value"
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.FxExtractor$Activation",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.IterableElementExtractor",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.ListElementExtractor",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.MapExtractor"
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.MapExtractor$ForKey",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.MapExtractor$ForValue",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.OptionalExtractor"
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.bval.jsr.valueextraction.OptionalExtractor$ForDouble",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.OptionalExtractor$ForInt",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "org.apache.bval.jsr.valueextraction.OptionalExtractor$ForLong",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.bval.jsr.valueextraction.OptionalExtractor$ForObject",
+      "methods": [
+        {
+          "name": "<init>",
+          "parameterTypes": []
+        }
+      ]
+    },
     {
       "condition": {
         "typeReached": 
"org.apache.shardingsphere.infra.config.rule.validator.RuleConfigurationValidator"
@@ -623,6 +828,11 @@
         "typeReached": 
"org.apache.shardingsphere.infra.config.rule.validator.RuleConfigurationValidator"
       },
       "type": 
"org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration",
+      "fields": [
+        {
+          "name": "type"
+        }
+      ],
       "methods": [
         {
           "name": "getType",
@@ -630,6 +840,102 @@
         }
       ]
     },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.infra.config.rule.validator.RuleConfigurationValidator"
+      },
+      "type": "javax.validation.constraints.NotEmpty",
+      "methods": [
+        {
+          "name": "message",
+          "parameterTypes": []
+        },
+        {
+          "name": "groups",
+          "parameterTypes": []
+        },
+        {
+          "name": "payload",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration",
+      "fields": [
+        {
+          "name": "type"
+        }
+      ],
+      "methods": [
+        {
+          "name": "getType",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": "javax.validation.constraints.NotEmpty",
+      "methods": [
+        {
+          "name": "message",
+          "parameterTypes": []
+        },
+        {
+          "name": "groups",
+          "parameterTypes": []
+        },
+        {
+          "name": "payload",
+          "parameterTypes": []
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.shardingsphere.data.pipeline.core.job.progress.config.PipelineProcessConfiguration",
+      "fields": [
+        {
+          "name": "read"
+        },
+        {
+          "name": "write"
+        },
+        {
+          "name": "streamChannel"
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.shardingsphere.data.pipeline.core.job.progress.config.PipelineReadConfiguration",
+      "fields": [
+        {
+          "name": "rateLimiter"
+        }
+      ]
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "type": 
"org.apache.shardingsphere.data.pipeline.core.job.progress.config.PipelineWriteConfiguration",
+      "fields": [
+        {
+          "name": "rateLimiter"
+        }
+      ]
+    },
     {
       "condition": {
         "typeReached": 
"org.apache.shardingsphere.infra.config.rule.validator.RuleConfigurationValidator"
@@ -1752,6 +2058,24 @@
       },
       "glob": 
"org/apache/bval/jsr/valueextraction/DefaultExtractors.properties"
     },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "bundle": "org.apache.bval.jsr.ValidationMessages"
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "glob": "org/apache/bval/jsr/DefaultConstraints.properties"
+    },
+    {
+      "condition": {
+        "typeReached": 
"org.apache.shardingsphere.data.pipeline.core.metadata.PipelineProcessConfigurationPersistService"
+      },
+      "glob": 
"org/apache/bval/jsr/valueextraction/DefaultExtractors.properties"
+    },
     {
       "condition": {
         "typeReached": 
"org.apache.shardingsphere.infra.spi.RegisteredShardingSphereSPI"
diff --git 
a/kernel/authority/api/src/main/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfiguration.java
 
b/kernel/authority/api/src/main/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfiguration.java
index 106fc233ad4..56c8a6e6eee 100644
--- 
a/kernel/authority/api/src/main/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfiguration.java
+++ 
b/kernel/authority/api/src/main/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfiguration.java
@@ -22,6 +22,7 @@ import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import 
org.apache.shardingsphere.infra.config.rule.scope.GlobalRuleConfiguration;
 import 
org.apache.shardingsphere.infra.config.rule.validator.constraint.spi.SPITypeExists;
+import 
org.apache.shardingsphere.infra.config.rule.validator.group.RuleConfigurationTypeValidationGroup;
 
 import javax.validation.Valid;
 import javax.validation.constraints.NotBlank;
@@ -41,10 +42,12 @@ public final class AuthorityRuleConfiguration implements 
GlobalRuleConfiguration
     private final Collection<@NotNull UserConfiguration> users;
     
     @NotNull
-    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.authority.spi.PrivilegeProvider")
+    @Valid
+    @SPITypeExists(spiClassName = 
"org.apache.shardingsphere.authority.spi.PrivilegeProvider", groups = 
RuleConfigurationTypeValidationGroup.class)
     private final AlgorithmConfiguration privilegeProvider;
     
     @NotNull
+    @Valid
     private final Map<@NotBlank String, @NotNull AlgorithmConfiguration> 
authenticators;
     
     private final String defaultAuthenticator;
diff --git 
a/kernel/authority/api/src/test/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfigurationTest.java
 
b/kernel/authority/api/src/test/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfigurationTest.java
index 8b2c0d08304..8b69b394338 100644
--- 
a/kernel/authority/api/src/test/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfigurationTest.java
+++ 
b/kernel/authority/api/src/test/java/org/apache/shardingsphere/authority/config/AuthorityRuleConfigurationTest.java
@@ -28,6 +28,8 @@ import java.util.Collections;
 import java.util.Properties;
 import java.util.stream.Stream;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -49,6 +51,8 @@ class AuthorityRuleConfigurationTest {
                         Collections.singleton(userConfig), privilegeProvider, 
Collections.emptyMap(), null)),
                 Arguments.of("User with null hostname", 
createRuleConfiguration(new UserConfiguration("foo_user", null, null, null, 
false))),
                 Arguments.of("User with empty hostname", 
createRuleConfiguration(new UserConfiguration("foo_user", null, "", null, 
false))),
+                Arguments.of("Whitespace authenticator type remains nonempty", 
new AuthorityRuleConfiguration(Collections.emptyList(), privilegeProvider,
+                        Collections.singletonMap("foo_authenticator", 
createAlgorithmConfiguration(" ")), null)),
                 Arguments.of("Complete configuration", new 
AuthorityRuleConfiguration(Collections.singleton(
                         new UserConfiguration("foo_admin", "foo_password", 
"localhost", "foo_authenticator", true)), privilegeProvider,
                         Collections.singletonMap("foo_authenticator", 
createAlgorithmConfiguration("MD5")), "foo_authenticator")));
@@ -58,6 +62,28 @@ class AuthorityRuleConfigurationTest {
         return new AlgorithmConfiguration(type, new Properties());
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("algorithmTypeArguments")
+    void assertValidateAlgorithmType(final String name, final 
AuthorityRuleConfiguration ruleConfig, final String expectedMessage) {
+        InvalidRuleConfigurationException actual = 
assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
+        assertThat(actual.getMessage(), is("Invalid 
'AuthorityRuleConfiguration' rule, error message is: " + expectedMessage));
+    }
+    
+    private static Stream<Arguments> algorithmTypeArguments() {
+        AlgorithmConfiguration privilegeProvider = 
createAlgorithmConfiguration("FIXTURE");
+        return Stream.of(
+                Arguments.of("Null privilege provider type before SPI", new 
AuthorityRuleConfiguration(Collections.emptyList(), 
createAlgorithmConfiguration(null), Collections.emptyMap(), null),
+                        "Property `privilegeProvider.type` Type is required."),
+                Arguments.of("Empty privilege provider type before SPI", new 
AuthorityRuleConfiguration(Collections.emptyList(), 
createAlgorithmConfiguration(""), Collections.emptyMap(), null),
+                        "Property `privilegeProvider.type` Type is required."),
+                Arguments.of("Whitespace privilege provider type reaches SPI", 
new AuthorityRuleConfiguration(Collections.emptyList(), 
createAlgorithmConfiguration(" "), Collections.emptyMap(), null),
+                        "Property `privilegeProvider` does not match an 
available SPI implementation."),
+                Arguments.of("Null authenticator type", new 
AuthorityRuleConfiguration(Collections.emptyList(), privilegeProvider,
+                        Collections.singletonMap("foo_authenticator", 
createAlgorithmConfiguration(null)), null), "Property 
`authenticators[foo_authenticator].type` Type is required."),
+                Arguments.of("Empty authenticator type", new 
AuthorityRuleConfiguration(Collections.emptyList(), privilegeProvider,
+                        Collections.singletonMap("foo_authenticator", 
createAlgorithmConfiguration("")), null), "Property 
`authenticators[foo_authenticator].type` Type is required."));
+    }
+    
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
     void assertValidateInvalidRuleConfiguration(final String name, final 
AuthorityRuleConfiguration ruleConfig) {
diff --git 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineProcessConfiguration.java
 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineProcessConfiguration.java
index 99064e12d69..d742f86b612 100644
--- 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineProcessConfiguration.java
+++ 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineProcessConfiguration.java
@@ -22,6 +22,8 @@ import lombok.RequiredArgsConstructor;
 import lombok.ToString;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 
+import javax.validation.Valid;
+
 /**
  * Pipeline process configuration.
  */
@@ -30,9 +32,12 @@ import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfigurat
 @ToString
 public final class PipelineProcessConfiguration {
     
+    @Valid
     private final PipelineReadConfiguration read;
     
+    @Valid
     private final PipelineWriteConfiguration write;
     
+    @Valid
     private final AlgorithmConfiguration streamChannel;
 }
diff --git 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineReadConfiguration.java
 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineReadConfiguration.java
index 7086aff61a9..4199264c04c 100644
--- 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineReadConfiguration.java
+++ 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineReadConfiguration.java
@@ -22,6 +22,8 @@ import lombok.RequiredArgsConstructor;
 import lombok.ToString;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 
+import javax.validation.Valid;
+
 /**
  * Pipeline read configuration.
  */
@@ -36,5 +38,6 @@ public final class PipelineReadConfiguration {
     
     private final Integer shardingSize;
     
+    @Valid
     private final AlgorithmConfiguration rateLimiter;
 }
diff --git 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineWriteConfiguration.java
 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineWriteConfiguration.java
index 859f4481501..bb93d52add3 100644
--- 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineWriteConfiguration.java
+++ 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/job/progress/config/PipelineWriteConfiguration.java
@@ -22,6 +22,8 @@ import lombok.RequiredArgsConstructor;
 import lombok.ToString;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 
+import javax.validation.Valid;
+
 /**
  * Pipeline write configuration.
  */
@@ -34,5 +36,6 @@ public final class PipelineWriteConfiguration {
     
     private final Integer batchSize;
     
+    @Valid
     private final AlgorithmConfiguration rateLimiter;
 }
diff --git 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/PipelineProcessConfigurationPersistService.java
 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/PipelineProcessConfigurationPersistService.java
index 735c0cd6f57..15b7af55646 100644
--- 
a/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/PipelineProcessConfigurationPersistService.java
+++ 
b/kernel/data-pipeline/core/src/main/java/org/apache/shardingsphere/data/pipeline/core/metadata/PipelineProcessConfigurationPersistService.java
@@ -18,18 +18,28 @@
 package org.apache.shardingsphere.data.pipeline.core.metadata;
 
 import com.google.common.base.Strings;
+import org.apache.bval.jsr.ApacheValidationProvider;
 import org.apache.shardingsphere.data.pipeline.core.context.PipelineContextKey;
 import org.apache.shardingsphere.data.pipeline.core.job.api.PipelineAPIFactory;
 import 
org.apache.shardingsphere.data.pipeline.core.job.progress.config.PipelineProcessConfiguration;
 import 
org.apache.shardingsphere.data.pipeline.core.job.progress.config.yaml.config.YamlPipelineProcessConfiguration;
 import 
org.apache.shardingsphere.data.pipeline.core.job.progress.config.yaml.swapper.YamlPipelineProcessConfigurationSwapper;
+import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.infra.util.yaml.YamlEngine;
 
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
 /**
  * Pipeline process configuration persist service.
  */
 public final class PipelineProcessConfigurationPersistService implements 
PipelineMetaDataPersistService<PipelineProcessConfiguration> {
     
+    private static final Validator VALIDATOR = 
Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory().getValidator();
+    
     private final YamlPipelineProcessConfigurationSwapper swapper = new 
YamlPipelineProcessConfigurationSwapper();
     
     @Override
@@ -39,12 +49,24 @@ public final class 
PipelineProcessConfigurationPersistService implements Pipelin
             return null;
         }
         YamlPipelineProcessConfiguration yamlConfig = 
YamlEngine.unmarshal(yamlText, YamlPipelineProcessConfiguration.class, true);
-        return swapper.swapToObject(yamlConfig);
+        PipelineProcessConfiguration result = swapper.swapToObject(yamlConfig);
+        validate(result);
+        return result;
     }
     
     @Override
     public void persist(final PipelineContextKey contextKey, final String 
jobType, final PipelineProcessConfiguration processConfig) {
+        validate(processConfig);
         String yamlText = 
YamlEngine.marshal(swapper.swapToYamlConfiguration(processConfig));
         
PipelineAPIFactory.getPipelineGovernanceFacade(contextKey).getMetaDataFacade().getProcessConfiguration().persist(jobType,
 yamlText);
     }
+    
+    private void validate(final PipelineProcessConfiguration processConfig) {
+        if (null == processConfig) {
+            return;
+        }
+        Collection<ConstraintViolation<PipelineProcessConfiguration>> 
violations = VALIDATOR.validate(processConfig);
+        ShardingSpherePreconditions.checkMustEmpty(violations,
+                () -> new 
IllegalArgumentException(violations.stream().map(ConstraintViolation::getMessage).distinct().sorted().collect(Collectors.joining(";
 "))));
+    }
 }

Reply via email to