From 7ab90c1a050d387ce30e32f72fbd0a95a611ef93 Mon Sep 17 00:00:00 2001 From: Peter Moser Date: Thu, 20 Aug 2026 13:16:28 +0200 Subject: [PATCH 1/3] add email validation --- .../validation/core/BaseRuleBuilder.java | 2 ++ .../validation/ValidationAssertTest.java | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/core/BaseRuleBuilder.java b/src/main/java/it/aboutbits/springboot/testing/validation/core/BaseRuleBuilder.java index 14e809f..dbe5a74 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/core/BaseRuleBuilder.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/core/BaseRuleBuilder.java @@ -1,6 +1,7 @@ package it.aboutbits.springboot.testing.validation.core; import it.aboutbits.springboot.testing.validation.rule.BetweenRule; +import it.aboutbits.springboot.testing.validation.rule.EmailRule; import it.aboutbits.springboot.testing.validation.rule.FutureRule; import it.aboutbits.springboot.testing.validation.rule.MaxRule; import it.aboutbits.springboot.testing.validation.rule.MinRule; @@ -35,6 +36,7 @@ public abstract class BaseRuleBuilder> implements ValidationRulesData, BetweenRule, + EmailRule, FutureRule, MaxRule, MinRule, diff --git a/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java b/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java index 4eb10b2..cfb8a42 100644 --- a/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java +++ b/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java @@ -6,6 +6,7 @@ import it.aboutbits.springboot.toolbox.type.ScaledBigDecimal; import it.aboutbits.springboot.toolbox.validation.annotation.ValidPassword; import jakarta.validation.Valid; +import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; @@ -188,6 +189,11 @@ public record SomeValidParameter( @ValidPassword String password, + // Email + @Email String email, + @Email @Nullable String nullableEmail, + @Email @NotBlank String requiredEmail, + // Not validated Object notValidated ) { @@ -333,6 +339,13 @@ void testWithBeanValidation() { // ValidPassword .validPassword("password", 8, 50) + // Email + .email("email") + .email("nullableEmail") + .nullable("nullableEmail") + .email("requiredEmail") + .notBlank("requiredEmail") + // Not validated .notValidated("notValidated") .isCompliant(); @@ -476,6 +489,13 @@ void invalidParameter_shouldFail() { // ValidPassword .validPassword("password", 8, 50) + // Email + .email("email") + .email("nullableEmail") + .nullable("nullableEmail") + .email("requiredEmail") + .notBlank("requiredEmail") + // Not validated .notValidated("notValidated") .isCompliant()); @@ -620,6 +640,13 @@ void propertyMissingRule_shouldFail() { // ValidPassword .validPassword("password", 8, 50) + // Email + .email("email") + .email("nullableEmail") + .nullable("nullableEmail") + .email("requiredEmail") + .notBlank("requiredEmail") + // Not validated .notValidated("notValidated") .isCompliant()); @@ -922,6 +949,11 @@ private static SomeValidParameter getSomeValidParameter() { // ValidPassword "password123", + // Email + "someone@example.com", + null, + "required@example.com", + // Not validated null ); From 95a4404746e7c71c6ea97d09ca2a6b2b58bbcb5b Mon Sep 17 00:00:00 2001 From: Peter Moser Date: Thu, 20 Aug 2026 13:17:48 +0200 Subject: [PATCH 2/3] add email validation --- .../testing/validation/rule/EmailRule.java | 24 ++++++++++ .../source/InvalidEmailValueSource.java | 47 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java create mode 100644 src/main/java/it/aboutbits/springboot/testing/validation/source/InvalidEmailValueSource.java diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java b/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java new file mode 100644 index 0000000..a3f102b --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java @@ -0,0 +1,24 @@ +package it.aboutbits.springboot.testing.validation.rule; + +import com.google.errorprone.annotations.CheckReturnValue; +import it.aboutbits.springboot.testing.validation.core.BaseRuleBuilder; +import it.aboutbits.springboot.testing.validation.core.Rule; +import it.aboutbits.springboot.testing.validation.core.ValidationRulesData; +import it.aboutbits.springboot.testing.validation.source.InvalidEmailValueSource; +import org.jspecify.annotations.NullMarked; + +@SuppressWarnings("unchecked") +@NullMarked +public interface EmailRule> extends ValidationRulesData { + /** + * Bean validation considers `null` and blank values to be valid e-mail addresses. + * Combine this rule with `notNull` or `notBlank` if the property must be present. + */ + @CheckReturnValue + default V email(String property) { + addRule( + new Rule(property, InvalidEmailValueSource.class) + ); + return (V) this; + } +} diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/InvalidEmailValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/InvalidEmailValueSource.java new file mode 100644 index 0000000..705b782 --- /dev/null +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/InvalidEmailValueSource.java @@ -0,0 +1,47 @@ +package it.aboutbits.springboot.testing.validation.source; + +import it.aboutbits.springboot.testing.validation.core.ValueSource; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; + +@NullMarked +public class InvalidEmailValueSource implements ValueSource { + private static final Map, Function>> TYPE_SOURCES = new HashMap<>(); + + static { + TYPE_SOURCES.put( + String.class, + (Object[] args) -> Stream.of( + "plainaddress", + "@example.com", + "someone@", + "someone@@example.com", + "some one@example.com", + "someone@exam ple.com", + "someone@example..com", + "someone@.example.com" + ) + ); + } + + @SuppressWarnings("unused") + public static void registerType(Class type, Function> source) { + TYPE_SOURCES.put(type, source); + } + + @Override + @SuppressWarnings("unchecked") + public Stream<@Nullable T> values(Class propertyClass, Object... args) { + var sourceFunction = TYPE_SOURCES.get(propertyClass); + if (sourceFunction != null) { + return (Stream<@Nullable T>) sourceFunction.apply(args); + } + + throw new IllegalArgumentException("Property class not supported!"); + } +} From dda852bd4b97ad35807cd3ff69090f0e2147cda6 Mon Sep 17 00:00:00 2001 From: Peter Moser Date: Thu, 20 Aug 2026 14:14:04 +0200 Subject: [PATCH 3/3] use markdown --- .../springboot/testing/validation/rule/EmailRule.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java b/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java index a3f102b..f3ad4d7 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/rule/EmailRule.java @@ -10,10 +10,8 @@ @SuppressWarnings("unchecked") @NullMarked public interface EmailRule> extends ValidationRulesData { - /** - * Bean validation considers `null` and blank values to be valid e-mail addresses. - * Combine this rule with `notNull` or `notBlank` if the property must be present. - */ + /// Bean validation considers `null` and blank values to be valid e-mail addresses. + /// Combine this rule with `notNull` or `notBlank` if the property must be present. @CheckReturnValue default V email(String property) { addRule(