Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -35,6 +36,7 @@
public abstract class BaseRuleBuilder<R extends BaseRuleBuilder<R>> implements
ValidationRulesData,
BetweenRule<R>,
EmailRule<R>,
FutureRule<R>,
MaxRule<R>,
MinRule<R>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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<V extends BaseRuleBuilder<?>> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<Class<?>, Function<Object[], Stream<?>>> 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<Object[], Stream<?>> source) {
TYPE_SOURCES.put(type, source);
}

@Override
@SuppressWarnings("unchecked")
public <T> Stream<@Nullable T> values(Class<T> 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!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
) {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -922,6 +949,11 @@ private static SomeValidParameter getSomeValidParameter() {
// ValidPassword
"password123",

// Email
"someone@example.com",
null,
"required@example.com",

// Not validated
null
);
Expand Down