Grails Custom Data Binding in 3 Simple Steps
The other day, Farid came with an interesting problem of binding a Time String to java.sql.Time. We straight away found the answer in using a CustomTimeEditor and registering it using a CustomPropertyEditorRegistrar bean. We were able to come arrive at this solution, thanks to this StackOverflow thread.
This set me thinking into using a CustomProperty Editor for, say a Cost object, which could contain a unit and an amount
[java]
class Cost{
String unit //Could be constrained to belong to some range of values
BigDecimal amount
}
[/java]
I was able to solve this issue in 3 simple steps which I would like to share with you. I felt that this would take a lesser amount of time compared to the Extended Data Binding Plugin(my gut feeling)
1. Add a CustomCostEditor to src/groovy
[java]
import java.beans.PropertyEditorSupportimport org.springframework.util.StringUtils
class CustomCostEditor extends PropertyEditorSupport { private final boolean allowEmpty
CustomCostEditor(boolean allowEmpty) {
this.allowEmpty = allowEmpty
}
@Override
void setAsText(String text) {
if (this.allowEmpty && !StringUtils.hasText(text)) {
// Treat empty String as null value.
setValue(null);
} else {
setValue(parse(text))
}
}
@Override
String getAsText() {
Cost cost = (Cost) getValue()
return "${cost.unit} ${cost.amount}"
}
Cost parse(String text){
try{
new Cost(unit: text.substring(0, text.indexOf(" ")), amount: text.substring(text.indexOf(" ") + 1).toBigDecimal())
} catch(Exception exception){
throw new IllegalArgumentException("Cost should be of the format ‘Unit Amount’")
}
}
}
[/java]
The methods which we need to override are setAsText() and getAsText()
2. Add a CustomPropertyEditorRegistrar class, which has a registerCustomEditorMethods
[java]
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar{
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Cost.class, new com.intelligrape.example.CustomCostEditor(true));
}
}
[/java]
3. Add a spring bean to add an instance of this custom property editor registrar
Finally, we create a spring bean by adding the following line in resources.groovy
[java]
beans = {
customPropertyEditorRegistrar(CustomPropertyEditorRegistrar)
}
[/java]
Now, assuming that we have an embedded field cost of type Cost in a domain class Item, we can simply use
[html]
<input type="text" name="cost" value="${fieldValue(bean: item, field:’cost’)}"/>
[/html]
and input “$ 123” to store $ in the cost.unit and 123 in the cost.amount.
I believe that the possibilities with such an approach are infinite!
Thanks for the post.
Have you gone further on the road with CompositePropertyEditor? I am struggling to make this approach work with a composite attribute.
Cheers
Alberto