{{announcement.body}}
{{announcement.title}}

Contextual Validation in Java

DZone 's Guide to

Contextual Validation in Java

In this post, we will consider the different ways to carry out validation, what is contextual validation, and why it beats all the other methods.

· Java Zone ·
Free Resource

Here, we will consider the different ways to carry out validation, what is contextual validation, and why it beats all the other methods.

You may also like: Validation in Java Applications

Context-Independent Validation Bound to Data-Model

Most of the current frameworks compel us, its users, to put validation in the data model. At least, the default mode for most of us is to simply bind validation rules to specific fields in the data model. What’s wrong with this approach?

Consider an example where a guest registers a new food delivery order. The company behind this service, which actually cooks the order, is called SuperFood. That’s how the whole user-story looks like:

Vasya as a guest visits SuperFood’s site and registered an order there.

SuperFood’s backend service must ensure several constraints before putting stuff in a database. One of them is to ensure that either email or phone number is passed.

Now suppose another user registers an order in SuperFood, but this time through some aggregator service, call it AggreA. This order doesn’t differ much from the one registered on SuperFood site, though the constraints to be enforced are different. For example, passing a phone number is essential for that aggregator, while email is optional.

Now, a third user registers an order in SuperFood, and she does it through some else aggregator service, AggreB. And for that one, passing a phone number is not needed, but email is a must.

So, we have the following situation. I have a single data-model for an order, but there are at least three contexts with a different set of constraints. I can go traditional way: introduce an entity corresponding to a database row, and impose those constraints through annotations or config files or whatever way I'me got used to. Data-model validation favors the following approach:

Java







Custom annotation ValidContactInfo eventually brings us to the custom validator, something like ContactInfoValidator. Its clearest implementation reflects the mental model of product-manager, which goes like the following (in a pseudo-code):

Java




xxxxxxxxxx
1


 
1
If order is being registered through site, then either email or phone number must be present.
2
If order is being registered through AggreA, phone is required.
3
If order is being registered through AggreB, email is required.



The primary objective is to find out somehow what exactly is the concrete scenario it operates within.

The data-model way implies that we should do that in a validator, taking fields from entity data-object. This way, I believe it is the least palatable one since we can’t use the power of the domain model and have to reside the validation logic in service classes. Simplified, it roughly looks like that:

Java







Now, imagine a mess your validation code turns into if a request gets more or less complex.

Arguably Better: Context-Independent Validation in Domain Objects

Often times, validation logic shown in the previous example gets out of control. In this case, it probably could be more beneficial to put it in a domain object responsible for business-logic. Besides, traditionally, it is a domain code that web developers tend to test-cover first. It could look like the following (mind the naming: I renamed Order to OrderFromRequest to stress the difference between it and domain order):

Java







But the problem of collecting errors and mapping them to UI arises. To my knowledge, there is no clean solution for that.

Contextual Validation That Is Specific to a Concrete User Story

For me, validation serves a clear purpose: to tell clients what exactly is wrong with their requests. But what exactly should go to validation? It depends on your take on the domain model. In my opinion, objects in the domain model represent context-independent “things” that can be orchestrated by a specific scenario in any possible way. They don’t hold any context-specific constraints. They check only universal rules, the ones that simply must be true, otherwise, that thing simply can’t be that thing. This reflects an always-valid approach when you simply can’t create an object in an invalid state.

For example, there is such a thing as courier id. It can only consist of UUID value. And I’ll definitely want to make sure that this is the case. It usually looks like the following:

Java







Introducing its own UUID interface with a couple of implementations would be even better:

Java







Typically, domain model invariants are quite basic and simple. All the other, more sophisticated context-specific checks belong to a specific controller (or Application service, or user-story). That’s where Validol comes in handy. You can first check basic, format-related validations, and proceed with however complicated ones.

Contextual Validation Example

Consider the following JSON request:

JSON







Validation could look like that:

Java







I admit it might look scary for anyone who sees the code for the first time and is totally unfamiliar with a domain. Fear not, things are not so complicated. Let’s consider what’s going on, line by line.

Lines 1-4: check whether the input request data represent well-formed JSON. Otherwise, fail fast and return a corresponding error.

Line 5: in case of well-formed JSON, a closure is invoked, and JSON data is passed.

Line 6: JSON structure is validated. The higher-level structure is an unnamed block of named entities. It closely resembles a Map.

Line 7: A list with a single named block is implied.

Line 11: It’s called delivery.

Line 10: It’s required.

Line 9: It must represent a JSON object.

Line 14: If all previous conditions are satisfied, closure is invoked. Otherwise, this whole thing fails fast and returns an appropriate error.

Line 15: A block named delivery consists of other named entities.

Line 19: Namely, where block. It’s not required though.

Line 20: If it’s present, closure is invoked.

Line 23: Block named where consists of other named entities.

Line 28: Namely, streetwhich is …

Line 27: … required;

Line 26: and is represented as a string.

Line 33: and building, which is …

Line 32: required as well;

Line 31: and should be represented as an integer.

Line 37: if all previous checks are successful, an object of the class Where is created. To be honest, it’s not a full-fledged object. It’s just a data-structure with convenient, type-hinted and IDE-autocompleted access to its fields.

Line 22: if underlying checks are passed, an address is ensured to exist. Mind the second argument, httpTransport. It’s for requesting some third-party service that checks an address existence.

Line 21: Aaaand, finally, we want to ensure that courier delivery is enabled in that area. We’ll need a database access for that, hence dbConnection argument.

Line 45: If everything was fine, a CourierDelivery object is created. It has a single argument, a Where class.

Line 49: Finally, OrderRegistrationRequestData object is created and returned.

I’ve intentionally put all the validating code in a single class. If the data-structure is really complex, I’d recommend to create a class per block. Check an example here.

Conclusion

So that’s pretty much it. This approach might (and actually does) look like overkill with such a simple request, though it shines with more complicated ones.

If you're interested in what else Validol library can do, check the documentation. A good place to start is this quick-start guide.

Further Reading

Validation in Java Applications

Spring RESTful Web Services Validation: A Complete Blueprint

Topics:
java ,validation ,declarative programming

Published at DZone with permission of Vadim Samokhin . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}