Grails has very good support for binding request parameters to a domain object and it's associations. This largely relies on detecting request parameters that end with
.id
class ProductCommand {
String name
Collection<AttributeTypeCommand> attributeTypes
ProductTypeCommand productType
}
ProductTypeCommand
AttributeTypeCommand
interface ProductAdminService {
Collection<AttributeTypeCommand> listAttributeTypes();
Collection<ProductTypeCommand> getProductTypes();
}
attributeTypes
productType
class ProductCommand {
ProductAdminService productAdminService
String name
List<Integer> attributeTypeIds = []
Integer productTypeId
void setProductType(ProductTypeCommand productType) {
this.productTypeId = productType.id
}
ProductTypeCommand getProductType() {
productAdminService.productTypes.find {it.id == productTypeId}
}
Collection<AttributeTypeCommand> getAttributeTypes() {
attributeTypeIds.collect {id ->
productAdminService.getAttributeType(id)
}
}
void setAttributeTypes(Collection<AttributeTypeCommand> attributeTypes) {
this.attributeTypeIds = attributeTypes.collect {it.id}
}
}
attributeTypeIds
productTypeId
productType
attributeTypes
Do you actually need to have sub-commands for attributeTypes and productType properties? Any reason you're not using PropertyEditorSupport binding? E.g.:
public class ProductTypeEditor extends PropertyEditorSupport
{
ProductAdminService productAdminService // inject somewhow
void setAsText(String s)
{
if (s) value = productAdminService.productTypes.find { it.id == s.toLong() }
}
public String getAsText()
{
value?.id
}
}
(and something similar for attributeType object), and register these in a editor registrar:
import java.beans.PropertyEditorSupport
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry reg) {
reg.registerCustomEditor(ProductType, new ProductTypeEditor())
reg.registerCustomEditor(AttributeType, new AttributeTypeEditor())
}
}
And register in your resources.groovy:
beans =
{
customEditorRegistrar(CustomEditorRegistrar)
}
then in your Cmd you just have:
class ProductCommand {
String name
List<AttributeType> attributeTypes = []
ProductType productType
}
If you do need actual sub-command associations then I've done something similar to what @Andre Steingress has suggested, in combination with PropertyEditorSupport binding:
// parent cmd
import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.FactoryUtils
public class DefineItemConstraintsCmd implements Serializable
{
List allItemConstraints = ListUtils.lazyList([], FactoryUtils.instantiateFactory(ItemConstraintsCmd))
//...
}
// sub cmd
@Validateable
class ItemConstraintsCmd implements Serializable
{
Item item // this has an ItemEditor for binding
//...
}
Hopefully I've not misunderstood what you're trying to achieve :)