Overview
FeatureValueConstraint defines constraints on product feature values, including type validation and value validation. Each constraint specifies the expected value type and validates whether a given value satisfies the constraint.
Package: com.softwarearchetypes.product
Source: /product/src/main/java/com/softwarearchetypes/product/FeatureValueConstraint.java:21
Interface
interface FeatureValueConstraint
Core interface for all feature value constraints.
Core Methods
valueType
FeatureValueType valueType()
Returns the type of values this constraint applies to.
The value type (TEXT, INTEGER, DECIMAL, DATE, or BOOLEAN)
type
Returns the constraint type identifier for persistence/deserialization.
Constraint type identifier (e.g., “ALLOWED_VALUES”, “NUMERIC_RANGE”, “REGEX”)
isValid
boolean isValid(Object value)
Validates whether the given value satisfies this constraint. The value must be of the correct type and meet the constraint’s specific requirements.
true if the value is valid, false otherwise
desc
Returns a human-readable description of this constraint.
Human-readable description (e.g., “one of: ” or “integer between 1 and 100”)
toString
default String toString(Object value)
Converts the object to its String representation for persistence.
The value to convert (must be valid)
fromString
default Object fromString(String value)
Converts a String representation to the object, applying validation.
The converted and validated object
Throws: IllegalArgumentException if the value cannot be parsed or is invalid.
Constraint Implementations
AllowedValuesConstraint
Restricts text values to a predefined set of allowed values.
Type identifier: ALLOWED_VALUES
Value type: TEXT
class AllowedValuesConstraint implements FeatureValueConstraint
Constructor
AllowedValuesConstraint(Set<String> allowedValues)
Set of allowed values (must not be empty)
Factory Method
static AllowedValuesConstraint of(String... values)
Creates an AllowedValuesConstraint from varargs.
Allowed values (must not be empty)
Example:
FeatureValueConstraint colorConstraint =
AllowedValuesConstraint.of("red", "blue", "green");
assert colorConstraint.isValid("red"); // true
assert !colorConstraint.isValid("yellow"); // false
assert colorConstraint.desc().equals("one of: [red, blue, green]");
allowedValues
Set<String> allowedValues()
Returns the set of allowed values.
Immutable set of allowed values
NumericRangeConstraint
Restricts integer values to a numeric range [min, max].
Type identifier: NUMERIC_RANGE
Value type: INTEGER
class NumericRangeConstraint implements FeatureValueConstraint
Constructor
NumericRangeConstraint(int min, int max)
Minimum value (inclusive)
Maximum value (inclusive, must be >= min)
Factory Method
static FeatureValueConstraint between(int min, int max)
Creates a NumericRangeConstraint.
Minimum value (inclusive)
Maximum value (inclusive)
Example:
FeatureValueConstraint yearConstraint =
NumericRangeConstraint.between(2020, 2024);
assert yearConstraint.isValid(2022); // true
assert !yearConstraint.isValid(2019); // false
assert !yearConstraint.isValid(2025); // false
assert yearConstraint.desc().equals("integer between 2020 and 2024");
min
Returns the minimum value.
max
Returns the maximum value.
DecimalRangeConstraint
Restricts decimal values to a range.
Type identifier: DECIMAL_RANGE
Value type: DECIMAL
Similar to NumericRangeConstraint but for BigDecimal values.
RegexConstraint
Validates text against a regex pattern.
Type identifier: REGEX
Value type: TEXT
Example:
FeatureValueConstraint emailConstraint =
new RegexConstraint("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
assert emailConstraint.isValid("[email protected]"); // true
assert !emailConstraint.isValid("invalid-email"); // false
DateRangeConstraint
Restricts dates to a range.
Type identifier: DATE_RANGE
Value type: DATE
Example:
FeatureValueConstraint dateConstraint =
new DateRangeConstraint(
LocalDate.of(2024, 1, 1),
LocalDate.of(2024, 12, 31)
);
assert dateConstraint.isValid(LocalDate.of(2024, 6, 15)); // true
assert !dateConstraint.isValid(LocalDate.of(2025, 1, 1)); // false
Unconstrained
Accepts any value of the specified type (no additional validation).
Type identifier: UNCONSTRAINED
Example:
FeatureValueConstraint anyText = Unconstrained.text();
assert anyText.isValid("any string"); // true
FeatureValueConstraint anyInteger = Unconstrained.integer();
assert anyInteger.isValid(42); // true
Usage Example
// Define a feature type with constraints
ProductFeatureTypeDefinition colorFeature = ProductFeatureTypeDefinition.builder()
.type(ProductFeatureType.of("Color"))
.constraint(AllowedValuesConstraint.of("Black", "White", "Silver"))
.build();
ProductFeatureTypeDefinition yearFeature = ProductFeatureTypeDefinition.builder()
.type(ProductFeatureType.of("ManufactureYear"))
.constraint(NumericRangeConstraint.between(2020, 2024))
.build();
// Validate feature values
FeatureValueConstraint colorConstraint = colorFeature.constraint();
assert colorConstraint.isValid("Black"); // true
assert !colorConstraint.isValid("Red"); // false
// Convert to/from String for persistence
String stored = colorConstraint.toString("Black");
Object restored = colorConstraint.fromString(stored);
assert restored.equals("Black");
// Invalid value throws exception
try {
colorConstraint.fromString("Red");
} catch (IllegalArgumentException e) {
// Exception message: "Invalid value: 'Red'. Expected: one of: [Black, White, Silver]"
}
Persistence Configuration
Constraints can be serialized to JSON for persistence:
AllowedValuesConstraint:
{
"type": "ALLOWED_VALUES",
"allowedValues": ["red", "blue", "green"]
}
NumericRangeConstraint:
{
"type": "NUMERIC_RANGE",
"min": 2020,
"max": 2024
}
RegexConstraint:
{
"type": "REGEX",
"pattern": "^[A-Z]{3}-\\d{4}$"
}