Announcement Announcement Module
Collapse
No announcement yet.
Doing validation in service layer Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Doing validation in service layer

    Hi,

    I am writing application with many different presentation platforms (web mvc is one of them), which implies that all functionality should be served through service layer and all validation should happen inside that layer. This is done using JSR-303 within AOP aspect, which throws custom runtime exception containing list of violated constraints on failure. This enables presentation layer to catch validation exception and provide verbose feedback to user - in case of web mvc this is done through translation from ConstraintViolation to spring BindingResult instance (just like in SpringValidatorAdapter) and adding errors to model.

    In code this looks like that:
    Code:
    public class ValidationException extends RuntimeException {
        public Set<javax.validation.ConstraintViolation> getViolatedConstraints();
    }
    
    @Service
    public interface SomeService {
        public void SomeAction(DomainObject someObject) throws ValidationException;
    }
    
    @Controller
    public class SomeController {
    
        public String handle(/* ... */) {
            /* ... */
    
            try {
                someService.SomeAction(someObject);
                // display success
            } catch(ValidationException  ex) {
                 BindingResult convertedBindingResult = MyValidationUtils.toBindingResult(ex.getViolatedConstraints(), someObject, "someObject")
                 map.add(convertedBindingResult.getModel())
                 // display failure
            }
        }
    
    }
    Question 1
    Is this architecture correct?
    /Question 1

    Everything seems correct, though, I have some problems due to separation of data binding and business validation. There may be some validation errors (namely type mismatches) detected in data binder and the question is how to handle them?

    For example imagine simple add user controller. User submits form filled with data, which spring web mvc binds to my domain User object. Unluckily real user entered string into integer type field, resulting in data binding error on Age property. Nevertheless, the object is passed to controller as method argument and controller is about to do its job. It should send user
    back to registration form with all errors listed. All errors, not just type mismatch messages, but also business violations on correctly entered fields (like not unique email address, name or some more complex rules like having to register exactly between 03:15 and 03:16AM ). The problem is it should call the service layer, since validation logic is there, but on the other hand it shouldn't, because if data binding error occurred on non-required field, then service layer will happily proceed, since that property value will be null.

    The problem in code:
    Code:
    @Controller
    public class SomeController {
    
        public String handle(@ModelAttribute SomeObject someObject, BindingResult bindingResult) {
            
            // what to do with bindingResult?!
    
            try {
                someService.SomeAction(someObject);
                // display success
            } catch(ValidationException  ex) {
                 BindingResult convertedBindingResult = MyValidationUtils.toBindingResult(ex.getViolatedConstraints(), someObject, "someObject")
                 map.add(convertedBindingResult.getModel())
                 // display failure
            }
        }
    
    }
    Question 2
    How to handle binding errors with validation done in service layer?
    /Question 2

    Solution A
    Simply don't call service layer if binding errors are detected. However this is not acceptable, because user will be informed only of type mismatch errors during first submit and business violations for correctly entered fields on second (e.g. not unique email, which is business level requirement). This is not user friendly and can lead to frustration.

    Solution B
    Add additional parameter to service layer method to pass previously detected violated constraints. Service method then checks if business validation rules were violated or any violations were passed. Additionally those passed violations should make validator to stop checking @NotNulls on certain properties, since there will be nulls due to data binding failure.

    Is there any better way? I just don't believe, that there is no simple way of doing it, since this seems like a pretty common usage.

    Regards
    Adrian

  • #2
    Same question here. *subscribing*

    Comment


    • #3
      Passing org.springframework.validation.Errors

      Have you considered just using org.springframework.validation. Errors as a Holder parameter in your service methods?

      I personally would keep myself away from Exception handling.

      In addition if you have constraints like "not unique email address" what is stopping you from using a org.springframework.validation.Validator for this matter or any other complicated business validation logic?

      Finally you can actually inject Validators and take advantage of some extra Spring Magic. Read http://static.springsource.org/sprin...alidation.html, section "Configuring Custom Constraints" for an example about JSR-303 integration.

      Best,
      -Nestor Urquiza

      Comment


      • #4
        Yup, Errors as additional parameter is what I described as Solution B and have implemented. However, I'm unsure if it's widely used approach.

        Why not to signal validation errors as exceptions? Out of returning them as function result, adding additional holder parameter or throwing them as exceptions, I prefer the last, or is there some other way?

        I'm using jsr-303 with custom constraints. What I'd like to stress in this thread is how to design communication between service and presentation layer. In spring documentation and examples, these two are combined together and there is no perfect-clean solution to separate them.

        Comment


        • #5
          Collecting Pattern

          1. I do not see the word web in org.springframework.validation.Errors
          2. Spring documentation ( http://static.springsource.org/sprin...alidation.html ) says:
          "Specifically validation should not be tied to the web tier, should be easy to localize and it should be possible to plug in any validator available. Considering the above, Spring has come up with a Validator interface that is both basic ands eminently usable in every layer of an application."

          That is clearly telling me I can use Errors or let us use a better word BindingResult in both Controller and Service layer.

          The solution is indeed clear.

          Now on the subject about exceptions one can argue that is just the way Java does its stuff == Exceptions but aren't we using Spring because (also) it favors the use of RuntimeException over Checked Exceptions all because we are too lazy to inundate our code with try/catch?

          I still think passing the Errors holder is a cleaner way. After all the "Collecting Pattern" has been there before Java was even invented. I cannot see how throwing and catching exceptions is making my team more agile on this purely validation matter.

          Makes sense?

          Cheers,
          -Nestor Urquiza

          Comment


          • #6
            New Validation Framework for Spring

            Izaak, I agree with your concern on the separation of validation from your service layer. Recently a colleague of mine and myself went about trying to solve this very issue and, finding JSR-303 and other validation patterns somewhat lacking, developed a small framework for use with Spring to make validation a simple process completely separated into its own layer that can be unobtrusively injected into your Controllers.

            Have a look at http://www.springjutsu.org/validation/summary

            We've got a quickstart as well as a fully functional example application that you can take a look at and comment on to let us know if this architecture seems better to you.

            For a quick idea of how it works, its a declarative validation framework using XML to map rules to either MVC url's or Webflow flows. We support nested and conditional validation rules. We also have support for using Spring's EL to validate things in your model as well as request and session attributes. And for Spring webflow we search Flash, View, Flow and Conversation scope (in order) to resolve expression paths.

            At any rate, I hope this helps you or anyone else interested in the issue of validation. Let me know if you have any questions or comments. Take care.

            -Taylor

            Comment

            Working...
            X