diff --git a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/OptionRule.java b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/OptionRule.java index 684620245c1..0d700bdbc11 100644 --- a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/OptionRule.java +++ b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/OptionRule.java @@ -165,7 +165,7 @@ public Builder conditional( @NonNull Option... requiredOptions) { verifyConditionalExists(conditionalOption); - if (expectValues.size() == 0) { + if (expectValues.isEmpty()) { throw new OptionValidationException( String.format( "conditional option '%s' must have expect values .", @@ -187,7 +187,7 @@ public Builder conditional( RequiredOption.ConditionalRequiredOptions option = RequiredOption.ConditionalRequiredOptions.of( expression, new ArrayList<>(Arrays.asList(requiredOptions))); - verifyRequiredOptionDuplicate(option); + verifyRequiredOptionDuplicate(option, true); this.requiredOptions.add(option); return this; } @@ -204,7 +204,7 @@ public Builder conditional( RequiredOption.ConditionalRequiredOptions.of( expression, new ArrayList<>(Arrays.asList(requiredOptions))); - verifyRequiredOptionDuplicate(conditionalRequiredOption); + verifyRequiredOptionDuplicate(conditionalRequiredOption, true); this.requiredOptions.add(conditionalRequiredOption); return this; } @@ -242,12 +242,30 @@ private void verifyDuplicateWithOptionOptions( } private void verifyRequiredOptionDuplicate(@NonNull RequiredOption requiredOption) { + verifyRequiredOptionDuplicate(requiredOption, false); + } + + /** + * Verifies if there are duplicate options within the required options. + * + * @param requiredOption The required option to be verified + * @param ignoreVerifyDuplicateOptions Whether to ignore duplicate option verification If + * the value is true, the existing items in OptionOptions are ignored Currently, it + * applies only to conditional + * @throws OptionValidationException If duplicate options are found + */ + private void verifyRequiredOptionDuplicate( + @NonNull RequiredOption requiredOption, + @NonNull Boolean ignoreVerifyDuplicateOptions) { requiredOption .getOptions() .forEach( option -> { - verifyDuplicateWithOptionOptions( - option, requiredOption.getClass().getSimpleName()); + if (!ignoreVerifyDuplicateOptions) { + // Check if required option that duplicate with option options + verifyDuplicateWithOptionOptions( + option, requiredOption.getClass().getSimpleName()); + } requiredOptions.forEach( ro -> { if (ro diff --git a/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/OptionRuleTest.java b/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/OptionRuleTest.java index 65c86d0f88e..cde60582091 100644 --- a/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/OptionRuleTest.java +++ b/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/OptionRuleTest.java @@ -31,6 +31,7 @@ import static org.apache.seatunnel.api.configuration.OptionTest.TEST_MODE; import static org.apache.seatunnel.api.configuration.OptionTest.TEST_NUM; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -155,6 +156,32 @@ public void testVerify() { assertEquals( "ErrorCode:[API-02], ErrorDescription:[Option item validate failed] - ConditionalRequiredOptions 'option.timestamp' duplicate in ConditionalRequiredOptions options.", assertThrows(OptionValidationException.class, executable).getMessage()); + + // Test conditional only does not conflict with optional options + // Test option TEST_TIMESTAMP + executable = + () -> { + OptionRule.builder() + .optional(TEST_NUM, TEST_MODE, TEST_TIMESTAMP) + .exclusive(TEST_TOPIC_PATTERN, TEST_TOPIC) + .required(TEST_PORTS) + .conditional(TEST_MODE, OptionTest.TestMode.TIMESTAMP, TEST_TIMESTAMP) + .conditional(TEST_MODE, OptionTest.TestMode.LATEST, TEST_TIMESTAMP) + .build(); + }; + assertDoesNotThrow(executable); + executable = + () -> { + OptionRule.builder() + .optional(TEST_NUM, TEST_MODE) + .exclusive(TEST_TOPIC_PATTERN, TEST_TOPIC, TEST_TIMESTAMP) + .required(TEST_PORTS) + .conditional(TEST_MODE, OptionTest.TestMode.TIMESTAMP, TEST_TIMESTAMP) + .build(); + }; + assertEquals( + "ErrorCode:[API-02], ErrorDescription:[Option item validate failed] - ConditionalRequiredOptions 'option.timestamp' duplicate in ExclusiveRequiredOptions options.", + assertThrows(OptionValidationException.class, executable).getMessage()); } @Test