4

I submit a form, lets say this form contains

<input name="address" ..>

and

<input name="billingAddress" ..>

i have 2 objects to which i need to bind to:

class Address {
   String address;
   ..
}

class BillingAddress {
   String address;
   ..
}

obviously billingAddress wont bind to address in BillingAddress without some magic.

lets say i have multiple identical fields in both Address and BillingAddress but on the form i prefix the billing inputs with billing, ie billingFirstName, billingLastName etc.

is there some elegant way i can bind to BillingAddress that i can reuse for similar problems?
(or is there a better way to solve this then what i have come up with?)

1 Answer 1

8

If you wand to use more than one ModelAttribute, you have to create a wrapper object, which holds an instance of each ModelAttribute. In your case I would create a wrapper object called "FormModel" which holds an instance of Address and an instance of a BillingAddress.

class FormModel {
  private Address address;
  private BillingAddress billingAddress;

  // Getters and Setters
}

Now use FormModel as your ModelAttribute. In your Form you can define your input-elements like:

<input name="address.address" ..>
<input name="billingAddress.address" ..>

Controller:

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(Model model, @ModelAttribute() FormModel formModel) {
   // process formModel.getAddress()
   // process formModel.getBillingAddress()

   return "redirect:home";
}

If you use custom validators for Address and BillingAddress, you also have to create a FormModelValidator that calls the AddressValidator and BillingAddressValidator:

public class FormModelValidator implements Validator {

    private final AddressValidator addressValidator;

    private final BillingAddressValidator billingAddressValidator;

    public FormModelValidator(AddressValidator addressValidator,
            BillingAddressValidator billingAddressValidator) {
        this.addressValidator = addressValidator;
        this.billingAddressValidator = billingAddressValidator;
    }

    public boolean supports(Class<?> clazz) {
        return FormModel.class.equals(clazz);
    }

    public void validate(Object target, Errors errors) {
        FormModel formModel = (FormModel) target;
        try {
            errors.pushNestedPath("address");
            ValidationUtils.invokeValidator(this.addressValidator,
                    formModel.getAddress(), errors);
        } finally {
            errors.popNestedPath();
        }
        try {
            errors.pushNestedPath("billingAddress");
            ValidationUtils.invokeValidator(this.billingAddressValidator,
                    formModel.getBillingAddress(), errors);
        } finally {
            errors.popNestedPath();
        }
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

that gives me a new problem ;) i try to validate the BillingAddress and AddressObjects using their own validators, but the BindingResult object refers to the FormModel object, and thus cannot locate any of the fields in error from the other 2 objects on it.
If I understand you right you have custom validators for Address and BillingAddress. In that case you have to create a FormModelValidator wich calls your custom validators. I added an example in my answer above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.