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
class Cost{ String unit //Could be constrained to belong to some range of values BigDecimal amount }
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
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'") } } }
The methods which we need to override are setAsText() and getAsText()
2. Add a CustomPropertyEditorRegistrar class, which has a registerCustomEditorMethods
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)); } }
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
beans = { customPropertyEditorRegistrar(CustomPropertyEditorRegistrar) }
Now, assuming that we have an embedded field cost of type Cost in a domain class Item, we can simply use
<input type="text" name="cost" value="${fieldValue(bean: item, field:'cost')}"/>
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