All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.javalin.core.validation.Validator.kt Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/*
 * Javalin - https://javalin.io
 * Copyright 2017 David Åse
 * Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
 */

package io.javalin.core.validation

import io.javalin.http.BadRequestResponse

open class Validator(val value: T?, val messagePrefix: String = "Value", val key: String = "Parameter") {

    data class Rule(val fieldName: String, val test: (T) -> Boolean, val invalidMessage: String)

    protected open var errors: MutableMap>? = null

    protected val rules = mutableSetOf>()

    @JvmOverloads
    open fun check(predicate: (T) -> Boolean, errorMessage: String = "Failed check"): Validator {
        rules.add(Rule(key, predicate, errorMessage))
        return this
    }

    //These two options will fail fast but only provide the first failure.
    fun get(): T = getOrNull() ?: throw BadRequestResponse("$messagePrefix cannot be null or empty")

    fun getOrNull(): T? {
        if (value == null) return null
        return rules.find { !it.test.invoke(value) }?.let { throw BadRequestResponse("$messagePrefix invalid - ${it.invalidMessage}") } ?: value
    }

    open fun isValid(): Boolean {
        if (errors == null) {
            validate()
        }
        return errors!!.isEmpty()
    }

    open fun hasError(): Boolean {
        if (errors == null) {
            validate()
        }
        return errors!!.isNotEmpty()
    }

    open fun errors(): Map> {
        if (errors == null) {
            validate()
        }
        return errors!!
    }

    protected open fun validate() {
        errors = mutableMapOf()
        rules.forEach { rule ->
            if (value != null) {
                try {
                    if (!rule.test.invoke(value)) {
                        if (!errors!!.containsKey(rule.fieldName)) {
                            errors!![rule.fieldName] = mutableListOf()
                        }
                        errors!![rule.fieldName]?.add(rule.invalidMessage)
                    }
                } catch (ignore: NullPointerException) {
                }
            }
        }
    }

    companion object {
        @JvmStatic
        @JvmOverloads
        fun  create(clazz: Class, value: String?, messagePrefix: String = "Value", key: String = "Parameter"): Validator {
            return Validator(try {
                val converter = JavalinValidation.converters[clazz] ?: throw MissingConverterException(clazz.simpleName)
                if (value != null && value.isNotEmpty()) {
                    converter.invoke(value) ?: throw NullPointerException()
                } else {
                    null
                }
            } catch (e: Exception) {
                if (e is MissingConverterException) throw e
                throw BadRequestResponse("$messagePrefix is not a valid ${clazz.simpleName}")
            } as T, messagePrefix, key)
        }

        @JvmStatic
        fun collectErrors(vararg validators: Validator<*>): Map> {
            return collectErrors(validators.toList())
        }

        @JvmStatic
        fun collectErrors(validators: Iterable>): Map> {
            val allErrors = mutableMapOf>()
            validators.forEach { validator ->
                validator.errors().forEach { (fieldName, errorMessages) ->
                    if (allErrors[fieldName] != null) {
                        allErrors[fieldName]?.addAll(errorMessages)
                    } else {
                        allErrors[fieldName] = errorMessages.toMutableList()
                    }
                }
            }
            return allErrors
        }
    }
}

fun Iterable>.collectErrors(): Map> {
    return Validator.collectErrors(this)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy