Rich Domain classes plugin
Dependency :
compile ":rich-domain:1.0.6"
Summary
This plugin provides dependency injection and validation support for POGO's that are NOT Grails domain classes.
Installation
grails install-plugin rich-domain
Description
Overview
The rich domain classes plugin provides dependency injection and validation support for POGO's (plain old groovy objects) that are NOT Grails domain classes.Dependency injection (auto wiring)
An AST transformation makes sure that auto wiring of dependencies is performed automatically after each constructor call and after deserialization. Hence no agents or other Spring AOP stuff is necessary.Usage
Add theWiredBean annotation to your class and use standard annotations like Inject and Resource to mark members that should be auto wired:
import be.ixor.grails.richdomain.autowire.WiredBean import javax.annotation.Resource import javax.inject.Inject import org.springframework.context.MessageSource import org.springframework.web.servlet.LocaleResolver@WiredBean class MyRichDomainClass { @Inject MessageSource injectedMessageSourceByType @Resource(name = "localeResolver") LocaleResolver injectedLocaleResolverByName LocaleResolver notInjectedLocalResolver }
Serializable will be wired again after deserialization. Injected fields should be marked as transient in this case.Testing
All objects are wired when running integration and functional tests. In unit tests, there is no appliction context and hence no wiring. You can however inject properties with aAutoWireBeanListener :
ApplicationContextUtils.autoWireBeanListener = {bean ->
if (bean instanceof MyBean) {
bean.foo = bar
}
} as AutoWireBeanListener@After
void clearAutoWireBeanListener() {
ApplicationContextUtils.autoWireBeanListener = null
}Validation support
The extended validation plugin adds declarative constraints and validation capabilities to classes that are not grails domain classes. The plugin is similar to the build-inValidationGrailsPlugin , but has a couple of extra features:
- constraint groups
- cascaded validation
- instance validators
- partial validation
- errors that survive serialization/de-serialization
The rich domain plugin supersedes the (deprecated) extended-validation plugin. The new plugin is based on AST transformations from Grails 2.x which has the advantage that validateable beans are not automatically added to the application context anymore. Furthermore the errors are now stored inside the bean and thus will survive (de)serialization.
Usage
Add thebe.ixor.grails.richdomain.validation.Validateable annotation to your class and define a static constraints closure:
@Validateable
class Person {
…
static constraints = …
}Listing classes in Config.groovy to make them validateable is not supported anymore.
Defining constraints
In addition to the standard grails constraints, the plugin provides some extra features.Constraint groups
You can define logical constraint groups. This is particularly useful in wizards, where the information comes from multiple pages and where one only wants to validate the fields on a certain page.static constraints = { personalDetails { firstName(blank: false) lastName(blank: false) } preferences { uiPrefs(validator: {...}) } }
Cascaded validation
Validation of nested objects can be achieved with thecascade constraint:
class Person {
…
Address address static constraints = {
address(cascade: true)
...Instance validation
Constraints that validate an instance rather than one field, don't need to be bound to a single field.static constraints = { maxNameLength(validator: { if(firstName.size() + lastName.size() > 50) return "nameToLong" }) ...
Partial validation
The dynamicvalidate method accepts three arguments: includes , excludes and groups // check all constraints person.validate()// only check included constraints person.validate(includes: ["firstName", "lastName"])// exclude specific (cascaded) constraints person.validate(excludes: ["firstName", "address.city"])// check only constraints in the specified groups, this will also limit cascaded validation to these groups person.validate(groups: ["personalDetails"])// exclude the constraints in the specified groups (excludeGroups are cascaded) person.validate(excludeGroups: ["personalDetails"])// all possible combinations are also valid: excludes are removed from the union of includes and groups person.validate(includes: ["address.*", "curriculum.companies.*"], groups: ["personalDetails"], excludes: ["address.street"])
Nested errors
All errors can recursively be fetched and cleared :assert person.allErrorsRecursive.size() == 3 person.clearErrorsRecursive()
Testing
Constraints and validation can be tested in plain unit tests without the need of special setup or mocks.Combining Validateable and WiredBean
Add thebe.ixor.grails.richdomain.RichDomain annotation to your class to get both auto wiring and validation support:
@RichDomain
class MyRichDomainClass {
@Inject
MessageSource injectedMessageSourceByType static constraints = {...}
}Changes
1.0.5
- Put all precompiled classes in lib/rich-domain-binaries.jar so that the AST transformations are always available
- Fixed bug in WiredBeanASTTransformation
- Added AutoWireBeanListener for easier unit testing