Business logic validation patterns & advices - java

I have two layers of validation in my application. First is entity validation performed by bean validation API (e.g. required fields).
The second level is business logic validation. For example, user has a post. User can delete a post only if he is a creator of this post and post rating < 50. So I have to do something like this:
if (post.getCreator().equals(session.getUser())) {
if (post.getRating() < 50) {
postRepository.delete(post);
} else errors.add(400, "Cant delete post with rating 50 or higher")
} else errors add (400, "You should be owner of the post")
I don't like this way as this conditionals are reused and I have to duplicate code. Moreover, if number of conditionals is greater than 5 or so it becomes unreal to read and understand the code.
Moreover, standard Spring Validator won't be very helpful as I have to maker different validation for one entity on different actions (delete and update for example)
So I'm looking for a way to do this in a smarter way (pattern maybe) and I would be very grateful if someone could give me a hint.
Thank in advance!

You can use the strategy pattern.
Each condition can be modelled as a function that takes a post and a session context and might return an error:
Post -> Session -> Optional<String>
You could represent this with an interface:
#FunctionalInterface
public interface ValidationCondition {
Optional<String> validate(final Post post, final Session session);
}
So for example:
public class CreatorValidation implements ValidationCondition {
public Optional<String> validate(final Post post, final Session session) {
if (post.getCreator().equals(session.getUser()) {
return Optional.empty();
}
return Optional.of("You should be the owner of the post");
}
}
You can then store every validation in a list:
final List<ValidationCondition> conditions = new ArrayList<>();
conditions.add(new CreatorValidation());
conditions.add(new ScoreValidation());
// etc.
Using the list, validations can be applied in bulk:
final List<String> errors = new ArrayList<>();
for (final ValidationCondition condition : conditions) {
final Optional<String> error = condition.validate(post, session);
if (error.isPresent()) {
errors.add(error.get());
}
}
Using Java 8 lambdas, you could declare these inline:
final ValidationCondition condition = (post, session) -> {
// Custom logic
});

Strategy pattern is the solution in my opinion.
I will give you a very simple example. Lets say we have two kinds of credit cards, Visa and Mastercard. The logic to perform payment operation is the same for both cards, but card number validation is different. So, by passing VisaStrategy object through a workflow does the same logic and operations as we would pass MastercardStrategy, except one thing - card number validation, which is done inside each defined Strategy class, so you do not have any "if else" stuff in your code at all. Each Strategy class is now responsible for one and only one type of card validation.
If you look for flexible and easy to maintain code structure - use Strategy design pattern.

Related

Checking "rules" in Java without lots of if statements

I'm creating a springboot banking API and in order to create a transaction a bunch of "rules" have to be checked.
e.g:
Current logged in user can't withdraw money from another user's savings account
Amount can't be higher/lower than certain number
etc.
This causes my createTransaction method to contain a lot of if statements (12!). This is what my code looks like in pseudo:
public ResponseEntity<String> createTransaction(Transaction body) {
if (check rule 1) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
if (check rule 2) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
// etc...
// Transaction complies to set rules
return ResponseEntity.status(HttpStatus.CREATED).body("Transaction successful!");
}
I can post my actual code if necessary but I think this paints the picture without having anyone to read 100 lines of code.
Because I have around 12 if statements checking these rules, my function is quite lengthy and difficult to read/maintain.
Googling for a solution didn't bring up results I was looking for. I've tried implementing exceptions but this didn't remove the amount of if statements. Maybe a switch could improve a bit, but I'm wondering if there's a clean OOP solution.
My question is: How can I clean this code up (OOP style)?
Thanks in advance.
You should create a TransactionRule interface that allows you to implement specific transaction rules, and then use a stream to get the final result:
public interface TransactionRule {
public boolean isAllowed(Transaction someTransaction);
}
Example implementation 1:
public class SufficientBudgetTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.wallet.value >= someTransaction.transaction.value;
}
}
Example implementation 2:
public class NotInFutureTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.transaction.datetime.isBefore(OffsetDateTime.now());
}
}
Then, you can store all the TransactionRules in a List and check whether they all validate like so:
private final List<TransactionRule> transactionRules; // Fill these of course
public boolean allTransactionRulesMatch(Transaction someTransaction) {
return transactionRules.stream()
.map(transactionRule -> transactionRule.isAllowed(someTransaction))
.allMatch(result => result);
}

Aggregate root validation on DDD deferred validation or always valid

I'm confused about aggregate root validation on DDD.
Where should i validate the children states when a child depends on another child?
For example, i have a billing context, which has the bill aggregate root. This root has a list of items,
a list of taxes and a list of invoices (a bill can have one or more invoices).
The sum of taxes should be lower or equal than the sum of items and the sum of invoices should be
lower or equal than the sum of items - taxes. And i can't have two invoices with same date and duplicated items.
I read that exists two approaches for the aggregate root state validation, the always valid and the deferred validation:
I thought of implementing an deferred validation using:
class BillService {
public Bill createBill(BillRequest billRequest) {
Bill bill = new Bill();
billRequest.getItems().forEach(item -> bill.addItem(item));
billRequest.getTaxes().forEach(tax -> bill.addTax(tax));
billRequest.getInvoices().forEach(invoice -> bill.addInvoice(invoice));
if (bill.isInvoicesSumValid()) {
throw new ...
}
return bill;
}
}
class Bill {
public void addItem(String itemId) {
if (invoices.stream().anyMatch(i -> i.getId().equals(itemId))) {
throw new ...
}
items.add(new BillItem(itemId, amount));
}
public void addInvoice(BigDecimal amount, LocalDate date) {
if (invoices.stream().anyMatch(i -> i.getDate().equals(date))) {
throw new ...
}
invoices.add(new BillInvoice(amount, date))
}
}
or the always valid approach:
class Bill {
private List<BillItem> billItems;
private List<BillTax> billTaxes;
private List<BillInvoices> billInvoices;
public Bill(..., List<BillItem> billItems, List<BillTax> billTaxes, List<BillInvoices> billInvoices) {
... //setting many other attributes
this.billItems = billItems;
this.billTaxes = billTaxes;
this.billInvoices = billInvoices;
validateDuplicatedItem();
validateDuplicatedDateInvoice();
validateInvoiceSum();
}
}
Using the deferred validation will make the aggregate root be on an invalid state, but seems easier to understand. Using the always valid approach will make the constructor giant and harder to understand.
Is there another way to solve this?
Both of these are technically valid, but there is a subtle difference between the two samples. In the always valid approach it is impossible to create a bill without all the proper information. In the deferred validation approach it is impossible for the BillService to create a bill with invalid info, but something else could. Your business rules should tell you which way to go.
If the many params in the Bill constructor bothers you, there’s nothing stopping you from passing in the BillRequest to the Bill constructor. In fact that approach would be easier for callers to work with because you could have an IsValid method on the BillRequest which callers could use to make sure their request is valid before trying to create the bill. It’s better to validate the incoming data as close to the source as possible.

How can I avoid repetitive if-else when validating fields in a DTO?

StudentDTO class having around 20 string attributes and each need to validate whether mandatory or not based on the logic given below in comments. This will make update method lengthy with too many if else's. Exception message should change based on the property evaluating. This code use Java 11.
// all fields except lastUpdated are string
public Student populateStudent(final StudentDTO studentDTO) {
Student student = new Student();
boolean dataUpdated = false;
/*
If mandatory parameter is:
1.) null : parameter is not updating
2.) empty : validate and throw an exception
3.) blank : validate and throw an exception
*/
if (isEmptyOrBlank(studentDTO.getName())) {
handleBadParam("Bad student name");
} else {
if (studentDTO.getName() != null) {
student.setName(studentDTO.getName());
dataUpdated = true;
}
}
if (isEmptyOrBlank(studentDTO.getBirthday())) {
handleBadParam("Bad student birthday");
} else {
if (studentDTO.getBirthday() != null) {
student.setBirthday(studentDTO.getBirthday());
dataUpdated = true;
}
}
// .... 20 other similar if-else statements later ....
// if atleast one parameter updated then date should update
if (dataUpdated) {
student.setLastUpdated(new Date());
}
return student;
}
private boolean isEmptyOrBlank(String name) {
return name != null && (name.isEmpty() || isBlank(name));
}
private void handleBadParam(String messgae) {
throw new IllegalArgumentException(messgae);
}
private boolean isBlank(String name) {
return (name.trim().length() == 0);
}
It seems you are validating your object.
I will not share any code example, I will just share an design opinion. By the way while designing your application, you should follow a design principle. So SOLID design principles is the commonly accepted, and you can apply these principles to your app while designing it.
You may create a class like StudentValidator so it's job must be only validating the Student object. So you realize first principle of solid's single responsibility.
And also that StudentValidator class will have methods which validations you need. And after all that implementations, you can cover in a method for each validation or you may call them when needed line.
Also there are many design patterns to avoid if-else statements via implementing patterns. Like command pattern, using enums etc.
I would strongly recommend to use the Java environment JSR 303 Bean Validation.The javax.validation packages provide developers with a standardized way of doing so. Fields that have to fulfill certain criteria receive the corresponding annotations, e.g. #NotNull, and these are then evaluated by the framework. Naturally, for checking more specific conditions, there is the possibility of creating custom annotations and validators.
You could refer to this https://dzone.com/articles/bean-validation-made-simple.

Java 8 Stateful consumer

Is conditional composition of Consumers possible in Java 8? Basically I'm looking to create a custom Lambda interface similar to Consumer but that only works with one type of object. Let's call it, Stateful and it contains multiple statuses (we'll say two for the purpose of this example):
public class Stateful {
private int status1;
private int status2;
}
We have a lot of areas in our code where we do an operation on a Stateful and, if the status has changed, we would do another operation. I was wondering if we could use composition to handle this in a more compact and elegant manner. Right now we would do something like:
SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2());
applyLogicOnStateful(stateful); //do some operation that may change state values
if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers
doSomethingElse(stateful);
}
where I think something like this would look better:
statefulConsumer
.accept((stateful)->applyLogicOnStateful(stateful))
.ifStatusChanged((stateful)->doSomethingElse(stateful));
but I don't know if we would be able to track the change in status from before the first consumer to after. Maybe I need to create a lambda that takes two consumers as input?
I'm definitely looking to do this without the assistance of a 3rd party library, although you're welcome to promote one here if it is helpful.
Here is a function that will return a Consumer<Stateful> that will extract the former state, do the change, compare results, and conditionally operate on the changed object.
public static Consumer<Stateful> getStatefulConsumer(
Function<Stateful,SimpleEntry<Integer,Integer>> getStatus, // extract status from Stateful
Consumer<Stateful> applyLogic, // apply business logic
BiPredicate<SimpleEntry<Integer,Integer>,SimpleEntry<Integer,Integer>> compareState, // test statuses for change
Consumer<Stateful> onChange) // doSomethingElse
{
return stateful -> {
SimpleEntry<Integer,Integer> oldStatus = getStatus.apply(stateful);
applyLogic.accept(stateful);
if(!compareState.test(oldStatus, getStatus.apply(stateful))){
onChange.accept(stateful);
}
};
}
You might use it like this:
Consumer<Stateful> ifChanged = getStatefulConsumer(s -> new SimpleEntry<> ( s.status1, s.status2 ),
s -> changeSomething(s), Objects::equals, s->doSomething(s));
You could generify the extracted status so that different stateful types could have different extracted status types, or even use Stateful::clone to copy the status.
The solution I am working with right now is to create a Lambda interface that takes the Stateful instance and two Consumers as input:
public interface StatefulConsumer {
void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer);
}
and an implementation:
final StatefulConsumer IfStateChanges = new StatefulConsumer() {
#Override
public void accept(Stateful stateful, Consumer<Stateful> consumer, Consumer<Stateful> ifStateChangedConsumer) {
SimpleEntry<Integer, Integer> oldStates = new SimpleEntry(stateful.getStatus1(), stateful.getStatus2());
consumer.accept(stateful); //do some operation that may change state values
if(isStatusChanged(oldStates, stateful) { //compare oldStates integers to status integers
ifStateChangedConsumer.accept(stateful);
}
}
};
which could be called like this:
IfStateChanges.accept(stateful,
(Stateful s)->applyLogicOnStateful(stateful),
(Stateful s)->doSomethingElse(stateful))
It could also be implemented as a Predicate or a Function that takes a stateful and a consumer as input and returns a boolean for use in an if Statement

Design pattern for cumulative validation violations

Let's imagine, that we have a process, which accepts data of the following type:
{"date":"2014-05-05", "url":"http://some.website.com","counter":3}
This data should be validated formally: value of date should be a
parseable date, url should also conform the normal url syntax.
Also, this data should be validated logically: date should be in the future, url should be an accessible
address, returning 200 OK.
To make it clean, one must separate those two validation routines into different units (classes, utils, whatever). The desired final behaviour, however, must give user clear understanding of ALL violations, that are present in data. Something like:
{"Errors":[
"Specified date is not in the future",//Formal validation failed
"Specified URL has invalid syntax"//Logical validation failed
]}
I have seen some implementations of the required behaviour, but they
use those make use of Error objects and are full of checks like
Error.hasErrors() or error==null, which does not look elegant.
I have also seen the implementation of javax.validation, which gives you all violations on all field at once. Same approach could be implemented for content validation, but I am not sure, that this is the best way to do this.
Question: what is the best practice for handling multiple exceptions/violations of various nature?
UPD: short digest of answers: collect Violations, build an Exception, containing their context, cause and description, use an interceptor to render. See reference links from answers:
http://beanvalidation.org/1.0/spec/ JSR 303 specification
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html Spring Bean Validation
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html Java EE validation
Which Design Pattern To Use For Validation
Why not use exceptions as regular flow of control?
You can do the following:
define an abstract Check class, as follows:
public abstract class Check {
private final List<Check> subChecks = new ArrayList<Check>();
public Check add(Check subCheck) { subChecks.add(subCheck); return this }
public void run(Data dataToInspect, List<Error> errors) {
Error e = check(dataToInspect);
if (e != null) {
errors.add(e);
return;
}
for (Check subCheck : subChecks) {
subCheck.run(dataToInspect, errors);
}
}
// Returns null if dataToInspect is OK.
public abstract Error check(Data dataToInspect);
}
class Data is the class holding the data (that needs to be checked). Can be a String, a JSON object, what have you.
class Error represents a problem detected in the data should be roughly something like:
public class Error {
private String problem;
public Error(String problem) { this.problem = problem }
public String getProblem() { return problem }
// maybe additional fields and method to better describe the detected problem...
}
You then have code that runs the check against piece of data:
public class Checker {
private final List<Error> errors = new ArrayList<Error>();
private final List<Check> checks = new ArrayList<Check>();
public Checker() {
checks.add(new DateIsParsableCheck().add(new DateIsInTheFurutreCheck());
checks.add(new UrlIsWellFormed().add(new UrlIsAccessible());
checks.add();
..
}
public void check(Data d) {
for (Check c : checks) {
Error e = c.run(d, errors);
if (e != null)
errors.add(e);
}
}
}
Slightly changed my original answer. In the current answer there is the notion of subchecks: if a check called x has a subcheck called y then the y check will run only if the x check succeeded. For instance, if the Date is not parseable there is no point to check it it is in the future.
In your case I think that all/most logical check should be sub-checks of a formal check.
I don't think there is a best practice, because it depends on what you try to achieve. In my opinion, exceptions and their messages should not be used to be displayed directly to the user. Exceptions are way too technical and do depend heavily on the context where they get thrown.
Hence, my approach would be to design a container type which collects all the exceptions thrown by your validations. Those exceptions should preserve as much of the context as possible (not in form of an exception message, but in form of fields passed into the constructor). Provide getter methods to make those fields (properties) accessible. When rendering the view, you may iterate over all entries of your container and generate a proper, human readable, i18n message.
Here is some pseudo-code as requested by the comment of #AlexandreSantos. It is not polished nor proven, just my first draft. So do not expect excellent design. It's just an example how it could be implemented / designed:
public static void main(String[] args) {
Violations violations = new Violations();
Integer age = AgeValidator.parse("0042", "age", violations);
URL url = UrlValidator.parse("http://some.website.com", "url", violations);
}
// Validator defining all the rules for a valid age value
public class AgeValidator {
// Collection of validation rules for age values
private static final Collection<Validator<String>> VALIDATORS = ...;
// Pass in the value to validate, the name of the field
// defining the value and the container to collect all
// violations (could be a Map<String, ValidationException>)
//
// a return value of null indicates at least one rule violation
public static Integer parse(String value, String name, Violations violations) {
try {
for (Validator<String> validator : VALIDATORS) validator.validate(value);
} catch (ValidationException e) {
violations.add(name, e);
}
return violations.existFor(name) ? null : Integer.parseInt(value);
}
}
I have answered this previously Here
The answer marked as good is an example of the Composite pattern being applied to validation (almost)
There are, of course, tons of frameworks for this. Something clever you could do, that I have used to great effect, is to use an aspect + a validator or make sure whole swaths of new and existing code get checked auto-magically.
#Aspect
public class DtoValidator {
private Validator validator;
public DtoValidator() {
}
public DtoValidator(Validator validator) {
this.validator = validator;
}
public void doValidation(JoinPoint jp){
for( Object arg : jp.getArgs() ){
if (arg != null) {
Set<ConstraintViolation<Object>> violations = validator.validate(arg);
if( violations.size() > 0 ){
throw buildError(violations);
}
}
}
}
private static BadRequestException buildError( Set<ConstraintViolation<Object>> violations ){
Map<String, String> errorMap = new HashMap<String, String>();
for( ConstraintViolation error : violations ){
errorMap.put(error.getPropertyPath().toString(), error.getMessage());
}
return new BadRequestException(errorMap);
}
}
Here is a snip of bean config
<aop:config proxy-target-class="true">
<aop:aspect id="dtoValidator" ref="dtoValidator" order="10">
<aop:before method="doValidation"
pointcut="execution(public * com.mycompany.ws.controllers.bs.*.*(..))"/>
</aop:aspect>
</aop:config>
Now all of your controller methods will have that validation code applied here and into the future.
Designing it using exceptions will work, but you will have to write a whole framework to deal with exceptions, many of which can't be handled by your exception interceptor. If you feel the coding itch, then go for it. My advice would be to have different classes of exceptions. Some of them would be critical exceptions, some would be just warnings... you got the picture.
You could (I hope you do) use a proven framework that can handle that beautifully. I speak of JSR 303 and Bean Validation through Spring: http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html
It takes a while to get used to, but it will pay you back 1000 fold.
I would simply pass around a list of all the errors. The items in the list may not be just exceptions, but rather some objects wrapping more information about the errors, such as name of wrong parameter, its wrong value, position of the error in the string, type of validation (formal, ligical), ID of the error message for localized display to user... Each method on the processing path may append to the list.

Categories

Resources