yavi
yavi copied to clipboard
Cross-field validation at different levels
Please add support for a cross-field validation at different levels, for example:
I have an object with type
and collection of items
:
record MyObject(
MyType type,
List<MyItem> items
){}
I need to be able to validate every item in collection depending on type
:
var validator = ValidatorBuilder.<MyObject>of()
.forEach(MyObject::items, "items", <there is no way to reference MyObject.type here>)
.build();
Thanks for the request. It makes sense to add that functionality.
@sergtitov Can you give me a more specific usage example?
It's true that you can't use it like the above, but I'd like to consider if there is an alternative to achieve what you want to do. I'm afraid it's probably difficult to implement the above approach with the current structure.
@making, we have several rules where fields validity on one level "depends" on the values of the fields on another level of an object.
Continuing the example from above where we have an object with type
and collection of items
:
record MyObject(
MyType type,
List<MyItem> items
){}
Validity of each element in items
collection depends on the type
, for some types an element would be valid, for others it would not.
For example:
record Animal(
AnimalType type,
List<String> actions
){}
The validator would need to be like this:
var validator = ValidatorBuilder.< Animal >of()
.forEach(Animal:: actions, "actions",
{
if parent.type == AnimalType.dog then check if action is one of ["run", "bark", ...]
if parent.type == AnimalType.cat then check if action is one of ["run", "meow", ...]
})
.build();
And the error message would be something like "For type dog an action "meow" is not allowed. Allowed values are: ["run", "bark", ...]"
Hi @making, is the example above is sufficient? Please let me know if you need more information. Thx!
I'm considering expanding the use of constraintOnCondition
to collection.
@sergtitov It seems that your case is already feasible using constraintOnCondition
.
Can you check the example? https://gist.github.com/making/facf1fce97c5d6686b017618c4959e15
Great work!
Hi @making I have a more complexe situation and I don't know if it's possible to solve it with yavi.
I have the following objects:
public class Customer {
public CustomerType type;
public InvoiceInformation invoiceInformation;
public static class InvoiceInformation {
public Object address;
public AdministrativeIdentifiers administrativeIdentifiers;
}
public static class AdministrativeIdentifiers {
public String fiscalCode;
public String pIva;
public String pec;
}
public enum CustomerType {
PRO, INHABITANT
}
}
my Administrative validator should be something like that:
public static Validator<AdministrativeIdentifiers> VALIDATOR = ValidatorBuilder.<AdministrativeIdentifiers>of()
.constraintOnCondition((a, g) -> isCustomerTypePro(), b -> b.constraint(AdministrativeIdentifiers::getFiscalCode, "fiscalCode", Constraint::notNull))
.build();
Where isCustomerTypePro
should check if the customer is a PRO or not.
Do you think there are a solution?
Thanks
@deblockt
The validation logic should be in the customer class.
import am.ik.yavi.builder.ValidatorBuilder;
import am.ik.yavi.core.Validator;
public class Customer {
public CustomerType type;
public InvoiceInformation invoiceInformation;
public boolean isCustomerTypePro() {
return this.type == CustomerType.PRO;
}
public CustomerType getType() {
return type;
}
public InvoiceInformation getInvoiceInformation() {
return invoiceInformation;
}
public static Validator<Customer> getValidator() {
return validator;
}
public static class InvoiceInformation {
public Object address;
public AdministrativeIdentifiers administrativeIdentifiers;
public Object getAddress() {
return address;
}
public AdministrativeIdentifiers getAdministrativeIdentifiers() {
return administrativeIdentifiers;
}
}
public static class AdministrativeIdentifiers {
public String fiscalCode;
public String pIva;
public String pec;
public String getFiscalCode() {
return fiscalCode;
}
public String getpIva() {
return pIva;
}
public String getPec() {
return pec;
}
}
public enum CustomerType {
PRO, INHABITANT
}
public static Validator<Customer> validator = ValidatorBuilder.<Customer>of()
.constraintOnCondition((customer, __) -> customer.isCustomerTypePro(),
b -> b.nest(Customer::getInvoiceInformation, "invoiceInformation",
ib -> ib.nest(InvoiceInformation::getAdministrativeIdentifiers, "administrativeIdentifiers",
ab -> ab.constraint(AdministrativeIdentifiers::getFiscalCode, "fiscalCode", c -> c.notNull()))))
.build();
}