简体   繁体   中英

Where the validation should be done in a 3 layers Entity-Repository-Service application?

I am struggling to define where the validation process would be better placed in the different layers of the application? (I am not talking about user input validation here, I'm really talking about the object consistency).

A simple case:

  • A Blog entity which has a field List<Comment> , and a method
    boolean addComment(Comment comment)
  • I want to check if the comment parameter of the boolean addComment(Comment comment) is null , which would return false

To me, such a check could be done in both the Service and Entity layers to ensure that everything is consistent at any layer.

But it seems redundant and something tells me that only one layer should have that responsability.

I would say the highest one in the stack, thus the Service layer should do this validation? But when I'm writing my unit tests, it feels wrong to not make that check again in the Entity layer.

My recommendation is to put these at the "public" interfaces to the services. With any public method you can't give any kind of guarantees as to the quality of input.

Here is the reasoning:

  • Services may present functionality to internal code clients
  • As well being exposed, through a controller, to a webservice.
  • Dao's should never be publicly exposed so they should never need entity validation. Realistically though, they will get exposed. If you make sure that only services call dao's (and only relevant services call appropriate dao's) Then you realize dao's are the wrong place
  • Services represent logical choke points to the code where easy validation can occurr.

The easiest way to enforce this logic is to create an aspect and put the validation code in there.

<aop:aspect ref="validator" order="3">
    <aop:before method="doValidation" pointcut="execution(public * com.mycompany.myapp.services.*.*(..))"/>"/>
</aop:aspect>

So, this aspect bean example covers all public methods in the service layer.

@Aspect
public class ServiceValidator{

    private Validator validator;

    public ServiceValidator() {
    }

    public ServiceValidator(Validator validator) {
        this.validator = validator;
    }

    public void doValidation(JoinPoint jp){
        for( Object arg : jp.getArgs() ){
            if (arg != null) {
                // uses hibernate validator
                Set<ConstraintViolation<Object>> violations = validator.validate(arg);
                if( violations.size() > 0 ){
                    // do something
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM