Creating a Kotlin DSL for validation

Posted by Sourced Blog on January 13, 2018
2249 words, 12 minute read

As a fan of Clean Architecture, I try to stay as close to its principles as possible. For example, the domain and application layers should have as little dependencies as possible and defer their technical choices to the infrastructure layers. In some cases, this may prove to be a harder exercise than you might imagine, but not an impossible one.

Take validation for example. We current have the Bean Validation 2.0 specification in Java at the moment, implemented by Hibernate Validator, the de facto choice for validation in most frameworks. However, this specification relies mainly on annotations which need to be put on the datastructures they validate. In the case of Clean Architecture, you’ll probably want to validate the input of your use cases. But that would mean a new dependency, the API for the Bean Validation spec, for the application API layer. Meh.

If you want to hide implementation details from a part of your application you’ll probably create an abstraction, so that’s what I started to build, in order to decouple my application API validation from any technical choice. And since I love using Kotlin, I thought a DSL might be a fun approach. Basically, I wanted my application API to define a validation specification which could then be converted into a real validation implementation in one of the infrastructure layers. I wanted to end up with something like this

After this, you can use the validator to validate your data structures. However, there are a couple of issues here. For starters, the name property is hardcoded and you can’t check whether the validated class actually has a name field. Secondly, there’s nothing that prohibits me from defining a EmailDef() constraints on an numeric field with this API. I think we can do a better job.

First, I define the data structures that make up the validation specification:

A ValidationSpec holds one or more Constraints for the different types, which in their turn define the various ConstraintRule’s for the FieldConstraint’s. A ConstraintRule is type-bound, in order to fulfill one of my constraints. So to implement the constraints needed in the DSL example, we need to provide a couple of implementations of ConstraintRule.

One of the fun parts of Kotlin is reified generics. This means that in some cases, you can get the type of a generic type parameter. For the constraints, this means we can do T::class, something that is impossible in Java. Otherwise we would have been forced to pass the type as a parameter, while now this can be inferred, making constraints<Foo> {...} possible, instead of resorting to constraints(Foo::class) {...} in the DSL.

So now that we have a implementation agnostic DSL that we can use in our application API, we need a translation mechanism that we can use in our infrastructure layer to translate the specification to a real validation implementation.

Here I’m using a built-in ConstraintDef from Hibernate Validator, but you can build your own if you want which means creating a new validation annotation, a validator for that annotation and a new ConstraintDef implementation.

While this was an interesting experiment, the code here is nowhere near production ready. But it clearly shows the viability of the underlying ideas. Writing Kotlin DSLs to create datastructures is incredibly powerful and allowed for strongly typed data structures and the enforcement of rules regarding allowed types. If I have the time, I’ll post a working example on Github, providing support for most of the constraints in the standard Bean Validator 2.0 spec.