Reputation: 73
I'm having a little issue with the result I'm getting with 'Combinator' pattern.
public interface CustomerRegistrationValidator
extends Function<Customer, ValidationResult> {
static CustomerRegistrationValidator isEmailValid() {
return customer -> customer.getEmail().contains("@") ?
ValidationResult.SUCCESS : ValidationResult.EMAIL_NOT_VALID;
}
static CustomerRegistrationValidator isPhoneNumberValid() {
return customer -> customer.getPhoneNumber().startsWith("+0") ?
ValidationResult.SUCCESS : ValidationResult.PHONE_NUMBER_NOT_VALID;
}
static CustomerRegistrationValidator isAnAdult() {
return customer -> Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
ValidationResult.SUCCESS : ValidationResult.IS_NOT_AN_ADULT;
}
default CustomerRegistrationValidator and (CustomerRegistrationValidator other) {
return customer -> {
ValidationResult result = this.apply(customer);
return result.equals(ValidationResult.SUCCESS) ? other.apply(customer) : result;
};
}
enum ValidationResult {
SUCCESS,
PHONE_NUMBER_NOT_VALID,
EMAIL_NOT_VALID,
IS_NOT_AN_ADULT
}
}
public class Main {
public static void main(String[] args) {
Customer customer = new Customer(
"Alice",
"alicegmail.com",
"089877878",
LocalDate.of(2000, 1, 1)
);
ValidationResult result = CustomerRegistrationValidator.isEmailValid()
.and(CustomerRegistrationValidator.isPhoneNumberValid())
.and(CustomerRegistrationValidator.isAnAdult())
.apply(customer);
System.out.println(result);
if (result != ValidationResult.SUCCESS) {
throw new IllegalStateException(result.name());
}
}
}
Let's say if there are two errors from those methods(isAnAdult, isEmailValid).Why does it print only one from enum types, in my case 'EMAIL_NOT_VALID' with exception instead of two and by the second one I mean 'IS_NOT_AN_ADULT' ?
Upvotes: 1
Views: 2703
Reputation: 1
In this modified code, the CustomerRegistrationValidator
interface now returns a List<CustomerRegistrationValidator.ValidationResult>
instead of a single ValidationResult
. Each validator method creates an empty list of errors and adds the relevant error to the list if the validation fails.
The and method has been updated to accumulate errors from both the current validator and the other validator. It creates a new list of errors, applies the current validator (this), and adds any errors to the list. Then it applies the other validator and adds any errors from that validator as well.
Now, when you apply the validators to a customer, you will get a list of errors instead of a single error. You can then handle the errors accordingly, such as printing them or performing any other necessary actions.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public interface CustomerRegistrationValidator extends Function<Customer, List<CustomerRegistrationValidator.ValidationResult>> {
static CustomerRegistrationValidator isEmailValid() {
return customer -> {
List<CustomerRegistrationValidator.ValidationResult> errors = new ArrayList<>();
if (!customer.getEmail().contains("@")) {
errors.add(CustomerRegistrationValidator.ValidationResult.EMAIL_NOT_VALID);
}
return errors;
};
}
static CustomerRegistrationValidator isPhoneNumberValid() {
return customer -> {
List<CustomerRegistrationValidator.ValidationResult> errors = new ArrayList<>();
if (!customer.getPhoneNumber().startsWith("+0")) {
errors.add(CustomerRegistrationValidator.ValidationResult.PHONE_NUMBER_NOT_VALID);
}
return errors;
};
}
static CustomerRegistrationValidator isAnAdult() {
return customer -> {
List<CustomerRegistrationValidator.ValidationResult> errors = new ArrayList<>();
if (Period.between(customer.getDob(), LocalDate.now()).getYears() <= 16) {
errors.add(CustomerRegistrationValidator.ValidationResult.IS_NOT_AN_ADULT);
}
return errors;
};
}
default CustomerRegistrationValidator and(CustomerRegistrationValidator other) {
return customer -> {
List<CustomerRegistrationValidator.ValidationResult> errors = new ArrayList<>();
errors.addAll(this.apply(customer));
errors.addAll(other.apply(customer));
return errors;
};
}
enum ValidationResult {
SUCCESS,
PHONE_NUMBER_NOT_VALID,
EMAIL_NOT_VALID,
IS_NOT_AN_ADULT
}
}
Customer customer = new Customer("Alice", "alicegmail.com", "089877878", LocalDate.of(2000, 1, 1));
List<CustomerRegistrationValidator.ValidationResult> errors = CustomerRegistrationValidator.isEmailValid()
.and(CustomerRegistrationValidator.isPhoneNumberValid())
.and(CustomerRegistrationValidator.isAnAdult())
.apply(customer);
if (!errors.isEmpty()) {
for (CustomerRegistrationValidator.ValidationResult error : errors) {
System.out.println(error);
}
// Handle the errors accordingly
} else {
// Registration is successful
}
Upvotes: 0
Reputation: 159114
If you want a validator to be able to return multiple distinct result codes (enums), then you need to change the return type to Set<ValidationResult>
, or more specifically an EnumSet
.
E.g. something like this:
interface CustomerRegistrationValidator
extends Function<Customer, EnumSet<ValidationResult>> {
static final EnumSet<ValidationResult> SUCCESS_ONLY = EnumSet.of(ValidationResult.SUCCESS);
static CustomerRegistrationValidator isEmailValid() {
return customer -> customer.getEmail().contains("@") ?
SUCCESS_ONLY : EnumSet.of(ValidationResult.EMAIL_NOT_VALID);
}
static CustomerRegistrationValidator isPhoneNumberValid() {
return customer -> customer.getPhoneNumber().startsWith("+0") ?
SUCCESS_ONLY : EnumSet.of(ValidationResult.PHONE_NUMBER_NOT_VALID);
}
static CustomerRegistrationValidator isAnAdult() {
return customer -> Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
SUCCESS_ONLY : EnumSet.of(ValidationResult.IS_NOT_AN_ADULT);
}
default CustomerRegistrationValidator and(CustomerRegistrationValidator other) {
return customer -> {
EnumSet<ValidationResult> thisResult = this.apply(customer);
EnumSet<ValidationResult> otherResult = other.apply(customer);
if (thisResult.equals(SUCCESS_ONLY))
return otherResult;
if (otherResult.equals(SUCCESS_ONLY))
return thisResult;
EnumSet<ValidationResult> combinedResult = EnumSet.copyOf(thisResult);
combinedResult.addAll(otherResult);
return combinedResult;
};
}
}
Upvotes: 5