Module is.codion.framework.domain
Interface EntityValidator
- All Known Implementing Classes:
DefaultEntityValidator
public interface EntityValidator
Responsible for providing validation for entities.
Entity validators enforce business rules and data integrity constraints beyond basic database constraints. They validate entity values before insert/update operations and can provide context-aware validation that considers the entity's current state and relationships.
Custom validators can be implemented for complex business logic:
// Custom validator for Customer entity
public class CustomerValidator implements EntityValidator {
@Override
public boolean valid(Entity customer) {
try {
validate(customer);
return true;
} catch (ValidationException e) {
return false;
}
}
@Override
public void validate(Entity customer) throws ValidationException {
// Validate email format
String email = customer.get(Customer.EMAIL);
if (email != null && !isValidEmail(email)) {
throw new ValidationException("Invalid email format: " + email);
}
// Business rule: Active customers must have email
Boolean active = customer.get(Customer.ACTIVE);
if (Boolean.TRUE.equals(active) &&
(email == null || email.trim().isEmpty())) {
throw new ValidationException("Active customers must have an email address");
}
// Age validation
LocalDate birthDate = customer.get(Customer.BIRTH_DATE);
if (birthDate != null && birthDate.isAfter(LocalDate.now().minusYears(13))) {
throw new ValidationException("Customer must be at least 13 years old");
}
}
@Override
public <T> void validate(Entity customer, Attribute<T> attribute)
throws ValidationException {
T value = customer.get(attribute);
if (attribute.equals(Customer.EMAIL)) {
String email = (String) value;
if (email != null && !isValidEmail(email)) {
throw new ValidationException("Invalid email format");
}
}
// Additional attribute-specific validation...
}
private boolean isValidEmail(String email) {
return email.contains("@") && email.contains(".");
}
}
// Usage in domain definition
Customer.TYPE.define(
Customer.EMAIL.define()
.column(),
Customer.ACTIVE.define()
.column(),
Customer.BIRTH_DATE.define()
.column())
.validator(new CustomerValidator())
.build();
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final PropertyValue
<Boolean> Specifies whether the default validator performs strict validation or not. -
Method Summary
Modifier and TypeMethodDescription<T> boolean
Returns true if the value based on the given attribute accepts a null value for the given entity, by default this method simply returns the nullable state of the underlying attribute.boolean
Returns true if the given entity contains only valid values.void
Checks if the values in the given entity are valid.<T> void
Checks if the value associated with the give attribute is valid, throws a ValidationException if not
-
Field Details
-
STRICT_VALIDATION
Specifies whether the default validator performs strict validation or not. By default, all non-read-only attribute values are validated if the entity is being inserted (as in, when it does not exist according toEntity.exists()
). If the entity exists, only modified values are validated. With strict validation enabled all values are validated, regardless of whether the entity exists or not- Value type: Boolean
- Default value: false
-
-
Method Details
-
nullable
Returns true if the value based on the given attribute accepts a null value for the given entity, by default this method simply returns the nullable state of the underlying attribute.// Context-aware nullable validation public class OrderValidator implements EntityValidator { @Override public <T> boolean nullable(Entity order, Attribute<T> attribute) { // Normally nullable, but not for shipped orders if (attribute.equals(Order.TRACKING_NUMBER)) { String status = order.get(Order.STATUS); return !"SHIPPED".equals(status); // Tracking number required when shipped } // Use default nullable behavior for other attributes return attribute.nullable(); } } // Usage during validation Entity order = entities.builder(Order.TYPE) .with(Order.STATUS, "SHIPPED") .build(); // No tracking number boolean canBeNull = validator.nullable(order, Order.TRACKING_NUMBER); // false
- Type Parameters:
T
- the value type- Parameters:
entity
- the entity being validatedattribute
- the attribute- Returns:
- true if the attribute accepts a null value
-
valid
Returns true if the given entity contains only valid values.- Parameters:
entity
- the entity- Returns:
- true if the given entity contains only valid values
-
validate
Checks if the values in the given entity are valid. Note that by default, if the entity instance does not exist according toEntity.exists()
all values are validated, otherwise only modified values are validated. Use theSTRICT_VALIDATION
configuration value to change the default behaviour.// Validation during entity lifecycle Entity customer = entities.builder(Customer.TYPE) .with(Customer.NAME, "John Doe") .with(Customer.EMAIL, "invalid-email") // Invalid format .with(Customer.ACTIVE, true) .build(); EntityValidator validator = entities.definition(Customer.TYPE).validator(); try { validator.validate(customer); // Validation passed connection.insert(customer); } catch (ValidationException e) { // Handle validation error System.err.println("Validation failed: " + e.getMessage()); // e.getMessage() might be: "Invalid email format: invalid-email" } // Check if entity is valid without throwing exception if (validator.valid(customer)) { connection.insert(customer); } else { // Handle invalid entity }
- Parameters:
entity
- the entity- Throws:
ValidationException
- in case of an invalid value- See Also:
-
validate
Checks if the value associated with the give attribute is valid, throws a ValidationException if not- Type Parameters:
T
- the value type- Parameters:
entity
- the entity to validateattribute
- the attribute the value is associated with- Throws:
ValidationException
- if the given value is not valid for the given attribute
-