21

I'm building a straight forward AJAX / JSON web service with Spring. The common data flow is:

  some DTO from browser

            v

Spring @Controller method

            v

  Spring @Service method

I'm looking for the most easy way to handle data validation.

  • I know the @Valid annotation which works pretty well inside @Controller methods.
  • Why does @Valid not work within @Service methods?

I mean: A service method can be used by any other service and controller. So wouldn't it make much more sense to validate at @Service level?


Let's take this simple example:

MyDTO.java:

public class MyDTO {
   @NotNull
   public String required
   @Min(18)
   public int age;
}

MyServiceImpl.java:

public MyDomainObject foo(MyDTO myDTO) {
  // persist myDTO
  // and return created domain object
}

MyController.java:

@Autowired
MyService myService;

@Autowired     // some simple bean mapper like Dozer or Orika
Mapper mapper; // for converting domain objects to DTO

@RequestMapping(...)
public MyDomainObjectDTO doSomething(@RequestBody MyDTO myDTO) {
  mapper.map(myService.foo(myDTO), MyDomainObjectDTO.class);
}

Is it common practice that the service method receives the DTO?

  • If yes: What's the best practice to validate that DTO inside the service method?
  • If no: Should maybe the controller manipulate the Domain object and just let the service save that object? (this seems pretty useless to me)

In my opinion the service should be responsible for only data consistency.

How do you solve this?

Benjamin M
  • 23,599
  • 32
  • 121
  • 201
  • possible duplicate of [Check preconditions in Controller or Service layer](http://stackoverflow.com/questions/11929781/check-preconditions-in-controller-or-service-layer) – Adam Gent Sep 30 '13 at 18:14

2 Answers2

27

My answer? Both.

The service must check its own contract for validity.

The controller is part of the UI. It should validate and bind for a better user experience, but the service should not rely on it.

The service cannot know how it's being called. What if you wrap it as a REST service?

The service also knows about business logic violations in a way that no UI can. It needs to validate to make sure that the use case is fulfilled appropriately.

Double bag it; do both.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • But then why the service doesn't allow `@Valid` annotations? ... I got your point, service and controller can use (for example) different fields in their classes. In my app, it's always the same. Because of this, I just pass through the DTO into the service. – Benjamin M Sep 30 '13 at 17:40
  • Because there is a difference between validation and defensive programming/error handling. That being said I do use validation for defensive programming. I'll post an answer soon. – Adam Gent Sep 30 '13 at 17:50
6

See my other answer: Check preconditions in Controller or Service layer

If you really want to do validation like error handling in your Service layer similar to Spring MVC you can use javax.validation and AspectJ (to advice the methods to validate) which is what I do because I like making reflection do the work and declarative programming (annotations).

Spring MVC doesn't need to do AspectJ/AOP to do the error handling because the methods are being called through reflection (url routing/dispatching).

Finally for you MVC code you should know that @Valid is sort of unofficially deprecated. Instead consider @Validated which will leverage more of the javax.validation features.

Community
  • 1
  • 1
Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • 1
    I now use `@Validated` at Service layer, which is pretty awesome. Just register Spring's `MethodValidationPostProcessor`, then put an `@Validated` annotation on the Service interface itself and last but not least put some `@Valid` or `@NotNull` annotations on the method signatures defined in the Service Interface. The ServiceImpl stays clean. This works extremely well! The only "problem" is, that the `propertyPath` within the thrown `ConstraintViolationException` get prefixed with the whole call hierarchy, i.e. `controllerMethod.serviceMethod.dtoProperty`. I must somehow get rid of this. – Benjamin M Jul 27 '15 at 07:01
  • What do you mean by 'sort of unofficially deprecated'? – prettyvoid Nov 01 '16 at 15:58