Closed rodrigodevelms closed 4 years ago
What’s the problem?
I have not found a method to add a custom validation, where I enter a string and get a boolean
Sorry, I don’t get your question.
https://github.com/making/yavi#custom Here is a way to add custom constraints.
I read it but I'm still lost. I'll explain better. I have the following class
data class User (
val name: String,
val lastName: String,
val cnpj: String
)
And I have the following function to validate the cnpj field
fun validarCnpj(cnpj: String): Boolean {
return validateCNPJLength(cnpj) && validateCNPJRepeatedNumbers(cnpj)
&& validateCNPJVerificationDigit(true, cnpj)
&& validateCNPJVerificationDigit(false, cnpj)
}
/**
* Verifies if the CNPJ has 14 digits.
*
* @return True if valid.
*/
private fun validateCNPJLength(cnpj: String) = cnpj.length == 14
/**
* Verifies if the CNPJ is not repeated numbers.
*
* A CNPJ with repeated is considered invalid, ex:
*
* '00000000000000'
* '11111111111111'
* '22222222222222'
* ...
* '88888888888888'
* '99999999999999'
*
* @return True if valid.
*/
private fun validateCNPJRepeatedNumbers(cnpj: String): Boolean {
return (0..9)
.map { it.toString().repeat(14) }
.map { cnpj == it }
.all { !it }
}
/**
* Verifies the CNPJ verification digit.
*
* This algorithm checks the verification digit (dígito verificador) do CNPJ.
* This was based from: https://www.devmedia.com.br/validando-o-cnpj-em-uma-aplicacao-java/22374
*
* @param[firstDigit] True when checking the first digit. False to check the second digit.
*
* @return True if valid.
*/
private fun validateCNPJVerificationDigit(firstDigit: Boolean, cnpj: String): Boolean {
val startPos = when (firstDigit) {
true -> 11
else -> 12
}
val weightOffset = when (firstDigit) {
true -> 0
false -> 1
}
val sum = (startPos downTo 0).fold(0) { acc, pos ->
val weight = 2 + ((11 + weightOffset - pos) % 8)
val num = cnpj[pos].toString().toInt()
val sum = acc + (num * weight)
sum
}
val result = sum % 11
val expectedDigit = when (result) {
0, 1 -> 0
else -> 11 - result
}
val actualDigit = cnpj[startPos + 1].toString().toInt()
return expectedDigit == actualDigit
}
And now I'm trying:
val validator: Validator<User> = ValidatorBuilder.of<User>()
.konstraint(User::name) {
notNull().message("Field name is required")
}
.konstraint(User::cnpj) {
notBlank().message("Field cnpj is required.")
.//now I wanted to insert the validation I created for cnpj, but I do not know how.
}
@rodrigodevelms I think this example is same as your case.
I'm trying to achieve almost the same here, except I need to validate an Instant
field. It happened so that there are no constraints against Instant class were defined. I made something like this:
fun <T> notNullCondition(property: KProperty1<T, Any?>) =
ConstraintCondition<T> { dto, _ -> property(dto) != null }
fun <T, V: Instant?> ValidatorBuilder<T>.instantConstraint(
property: KProperty1<T, V>,
getStart: () -> Instant = Instant::now,
getEnd: () -> Instant = { Instant.MAX },
errorTemplate: String = "Instant value {0} is illegal",
chain: ValidatorBuilder<T>.(ValidatorBuilder<T>) -> Unit = { }
): ValidatorBuilder<T> {
val whenTimeIsBad = Predicate<T> {
val value = property(it)
if (value == null) true
else getStart() <= value && value <= getEnd()
}
konstraintOnCondition(notNullCondition(property)) {
constraintOnTarget(whenTimeIsBad, property.name, "custom.instant", errorTemplate)
chain(this)
}
return this
}
It works fine, except for a problem with dynamic boundaries for the checks that I want to have in my error message.
So, I have two questions:
errorMessage
?Thank you.
@night-crawler Would you mind converting your snippet to Java so that I can understand you case well?
I'm still not sure if providing constraints on date/time type is useful.
Bean Validation has @Past
, @PastOrPresent
, @Future
and @FutureOrPresent
that I have never used. Maintaining date/time constraints is not that easy as it needs to support a lot of types (JSR-310 and legacy types). So I'd like to understand if it is really helpful.
@making I'll try to come up with something in Java later, but honestly, I've never written more than 10 lines of code in Java, so I need some time to do that :)
Also, the sole purpose of this check is to ensure that validTill
date is in the future.
BTW, what about adding some runtime information in error message (except for the args that are already provided)?
@night-crawler
BTW, what about adding some runtime information in error message (except for the args that are already provided)?
What type of output do you expect? I don't get it from your sample.
@making
In my example, I want to put the current Instant
in the message (both from getStart()
and getEnd()
callbacks).
@night-crawler I got it and it makes sense to support that for custom constraints. I'm closing this issue as this issue does not seem to be the right place to discuss further. I've created new issues to support your requests #36 #37
I have a validation that takes a string and returns a boolean. As I enter in the other validations. Example: