Domain Object Validation
A couple of questions about domain object validation:
1. What is the separation of concerns argument for keeping validation outside of a domain object (but still within the domain layer)? It seems like that breaks good OOD encapsulation. To quote J2EE Development Without EJB: "However, the principle of separating validation rules from the validated objects is important." p. 377. Why shouldn't my domain objects implement the Validator interface?
2. What is the best way to implement domain object validation within the Spring framework? The Spring documentation on this topic is disturbingly sparse. There seems to be a lot of interest in presentation layer validation and documenting how to integrate Apache Commons Validator, but not a whole lot on how to actually implement validation at the domain object level using what seems to be an otherwise brilliantly simple implementation of validation within org.springframework.validation. I don't need declarative validation and frankly, Chapter 4 of the reference documentation is pretty weak. I just want simple validation at the domain object level for batch processing(:shock:) that doesn't involve a GUI.
My initial reaction would be to do internal validation and throw Exceptions if/when it fails for Domain level validation. For input validation I think the Spring validator is a good way of keeping presentation format / translation logic seperate from the Domain objects, but I won't try and use it inside the Domain object's. With Spring's flexible exception handling you can translate you Domain exceptions into error pages, etc.. depending on the situation.
In most Spring apps, DO properites have three "audiences":
- Business object method themselves, to do special logic
- Hibernate or similar for persistence
- Spring MVC or similar for binding to form properties
If you start making DO setters enforce their state, you get a beautiful OO-centric design, but they become almost impossible to use for persistence or MVC form binding. Ditto for constructors. It's nice to use constructors to ensure a DO is never in an invalid state, but again this stops you using them easily with persistence or MVC form binding.
Naturally, you could do two object layers. Your DOs could actually contain true business logic, fully enforce setters and constructors etc, and then you have a separate DTO layer which are simply getters and setters, with the idea of using them with persistence and web views. However, you'll have a lot of copying being performed and it just doesn't seem too attractive in most cases.
We found a compromise between these various factors which I've previously discussed at http://forum.springframework.org/showthread.php?t=11293. Nothing is perfect. In this case we make the DO aware of the Spring validator interface, and have an interceptor ensure it gets executed prior to persistence. Similarly, the DOs call the validator before actual business methods are executed. Thus we can be pretty sure objects have valid state by the time they're "used", but validation can be deferred and thus ensure compatibility with those infrastructure services expecting simple JavaBean style objects. It also works in neatly with Spring MVC and where it expects validation to occur.
Domain Object Validation
Thanks for the responses.
1. I'm still looking for the rationale for separating validation rules from domain objects. In the responses I've gotten so far, the domain object itself is responsible for the validation. This despite the fact that the JPetstore application has the validation in separate classes (e.g. AccountValidator and OrderValidator) within the domain layer. Hopefully someone will argue the "separate validation from domain objects" case.
2. It sounds like rrsIPOV doesn't use the Spring validation framework from within the domain objects but stuck with domain-based validation and custom exceptions. I'm not sure how that works when you stick a GUI on top of it and whether or not you'd have to end up implementing Spring's validation framework anyway.
Ben it looks like you are still using a the core of the validation framework provided by Spring (e.g. BindException, Errors and Validator). However, I didn't quite understand why your abstract BusinessObject (probably should have been DomainObject) didn't implement the Validate interface and why a separate bindsupport() method was necessary. Do you see any role for DataBinder in domain object validation or is this a job for the DAOs?
The key reason I keep the Validator in a separate class from my domain object themselves is:
1. The Validator implementation comes from a Spring IoC container. As such it is a singleton and is nicely autowired with DAOs that are used in the validation process. The alternative of having each domain object implementing Validator themselves and thus needing access to all these DAOs seems a bit unnecessary.
2. More importantly, using the separate Validator means it can be used directly in Spring MVC. Spring MVC's classes expect the Validator to be a separate bean, so this was a major reason to do it that way.