Home » JVM Languages » Kotlin » Validation in Kotlin: Valiktor

About Michael Scharhag

Michael Scharhag
Michael Scharhag is a Java Developer, Blogger and technology enthusiast. Particularly interested in Java related technologies including Java EE, Spring, Groovy and Grails.

Validation in Kotlin: Valiktor

Bean Validation is the Java standard for validation and can be used in Kotlin as well. However, there are also two popular alternative libraries for validation available in Kotlin: Konform and Valiktor. Both implement validation in a more kotlin-like way without annotations. In this post we will look at Valiktor.

Getting started with Valiktor

First we need to add the Valiktor dependency to our project.

For Maven:

1
2
3
4
5
<dependency>
  <groupId>org.valiktor</groupId>
  <artifactId>valiktor-core</artifactId>
  <version>0.12.0</version>
</dependency>

For Gradle:

1
implementation 'org.valiktor:valiktor-core:0.12.0'

Now let’s look at a simple example:

1
2
3
4
5
6
7
8
class Article(val title: String, val text: String) {
    init {
        validate(this) {
            validate(Article::text).hasSize(min = 10, max = 10000)
            validate(Article::title).isNotBlank()
        }
    }
}

Within the init block we call the validate(..) function to validate the Article object. validate(..) accepts two parameters: The object that should be validated and a validation function. In the validation function we define validation constraints for the Article class.

Now we try to create an invalid Article object with:

1
Article(title = "", text = "some article text")

This causes a ConstraintViolationException to be thrown because the title field is not allowed to be empty.

More validation constraints

Let’s look at a few more example validation rules:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
validate(this) {
    
    // Multiple constraints can be chained
    validate(Article::authorEmail)
            .isNotBlank()
            .isEmail()
            .endsWith("@cool-blog.com")
    // Nested validation
    // Checks that Article.category.name is not blank
    validate(Article::category).validate {
        validate(Category::name).isNotBlank()
    }
    // Collection validation
    // Checks that no Keyword in the keywords collection has a blank name
    validate(Article::keywords).validateForEach {
        validate(Keyword::name).isNotBlank()
    }
    // Conditional validation
    // if the article is published the permalink field cannot be blank
    if (isPublished) {
        validate(Article::permalink).isNotBlank()
    }
}

Validating objects from outside

In the previous examples the validation constraints are implemented within the objects init block. However, it is also possible to perform the validation outside the class.

For example:

1
2
3
4
5
val person = Person(name = "")
validate(person) {
    validate(Person::name).isNotBlank()
}

This validates the previously created Person object and causes a ConstraintViolationException to be thrown (because name is empty)

Creating a custom validation constraint

To define our own validation methods we need two things: An implementation of the Constraint interface and an extension method. The following snippet shows an example validation method to make sure an Interable<T> does not contain duplicate elements:

01
02
03
04
05
06
07
08
09
10
11
12
13
object NoDuplicates : Constraint
fun <E, T> Validator<E>.Property<Iterable<T>?>.hasNoDuplicates()
        this.validate(NoDuplicates) { iterable: Iterable<T>? ->
    if (iterable == null) {
        return@validate true
    }
    val list = iterable.toList()
    val set = list.toSet()
    set.size == list.size
}

This adds a method named hasNoDuplicates() to Validator<E>.Property<Iterable<T>?>. So this method can be called for fields of type Iterable<T>. The extension method is implemented by calling validate(..) with our Constraint and passing a validation function.

In the validation function we implement the actual validation. In this example we simply convert the Iterable to a List and then the List to a Set. If duplicate elements are present both collections have a different size (a Set does not contain duplicate elements).

We can now use our hasNoDuplicates() validation method like this:

1
2
3
4
5
6
7
class Article(val keywords: List<Keyword>) {
    init {
        validate(this) {
            validate(Article::keywords).hasNoDuplicates()
        }
    }
}

Conclusion

Valiktor is an interesting alternative for validation in Kotlin. It provides a fluent DSL to define validation rules. Thoes rules are defined in standard Kotlin code (and not via annotations) which makes it easy to add conditional logic. Valiktor comes with many predefined validation constraints. Custom constraints easily be implemented using extension functions.

Published on Java Code Geeks with permission by Michael Scharhag, partner at our JCG program. See the original article here: Validation in Kotlin: Valiktor

Opinions expressed by Java Code Geeks contributors are their own.

(0 rating, 0 votes)
You need to be a registered member to rate this.
Start the discussion Views Tweet it!
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments