Is this a code smell, or is it the best way to implement cross-field validation in a Spring form?
@FieldRequiredIf.List({
@FieldRequiredIf(ifField="firstHomePhoneNumber", matches={EMPTY, NULL},require ="firstMobilePhoneNumber",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.firstMobilePhoneNumber",groups=FirstLife.class),
@FieldRequiredIf(ifField="secondHomePhoneNumber", matches={EMPTY,NULL},require ="secondMobilePhoneNumber",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.secondMobilePhoneNumber",groups=SecondLife.class),
@FieldRequiredIf(ifField="lifeAssuredIsPolicyOwner", matches={FALSE},require ="policyOwnerName",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.policyOwnerName"),
@FieldRequiredIf(ifField="lifeAssuredIsPolicyOwner", matches={FALSE},require ="policyOwnerAddress",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.policyOwnerAddress"),
@FieldRequiredIf(ifField="insurableInterest", matches={InsurableInterestConstants.OTHER},require ="insurableInterestReason",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.insurableInterestReason",groups = NonSingleNonMortgage.class),
@FieldRequiredIf(ifField="firstAddress2", matches={NOT_EMPTY},require ="firstAddress1",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.firstAddress1",groups=FirstLife.class),
@FieldRequiredIf(ifField="firstAddress3", matches={NOT_EMPTY},require ="firstAddress2",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.firstAddress2",groups=FirstLife.class),
@FieldRequiredIf(ifField="firstAddress4", matches={NOT_EMPTY},require ="firstAddress3",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.firstAddress3",groups=FirstLife.class),
@FieldRequiredIf(ifField="firstAddress5", matches={NOT_EMPTY},require ="firstAddress4",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.firstAddress4",groups=FirstLife.class),
@FieldRequiredIf(ifField="secondAddress2", matches={NOT_EMPTY},require ="secondAddress1",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.secondAddress1",groups=SecondLife.class),
@FieldRequiredIf(ifField="secondAddress3", matches={NOT_EMPTY},require ="secondAddress2",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.secondAddress2",groups=SecondLife.class),
@FieldRequiredIf(ifField="secondAddress4", matches={NOT_EMPTY},require ="secondAddress3",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.secondAddress3",groups=SecondLife.class),
@FieldRequiredIf(ifField="secondAddress5", matches={NOT_EMPTY},require ="secondAddress4",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.secondAddress4",groups=SecondLife.class)
})
public class CorrespondenceDetailsForm {
...
}
As an attempt to simplify the above, I started refactoring a couple of logical groups of these listed annotations into single custom annotations: (@FirstLifeContactDetailsObserver and @SecondLifeContactDetailsObserver). Here's the refactored class level annotations:
@FieldRequiredIf.List({
@FieldRequiredIf(ifField="lifeAssuredIsPolicyOwner", matches={FALSE},require ="policyOwnerName",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.policyOwnerName"),
@FieldRequiredIf(ifField="lifeAssuredIsPolicyOwner", matches={FALSE},require ="policyOwnerAddress",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.policyOwnerAddress"),
@FieldRequiredIf(ifField="insurableInterest", matches={InsurableInterestConstants.OTHER},require ="insurableInterestReason",elseDisplay = "FieldRequiredIf.correspondenceDetailsForm.insurableInterestReason",groups = NonSingleNonMortgage.class)
})
@FirstLifeContactDetailsObserver
@SecondLifeContactDetailsObserver
public class CorrespondenceDetailsForm {
...
}
This hasn't really improved the situation though, as I need a validator class for each new annotation.
Is there a better way of doing cross-field validation in Spring MVC?
That's the way you would do it in Spring. You might want to take a look at how far JSF has developed and reevaluate if Spring is still your number one choise. Seams might help with neater mulitple field validation.
Just to finish this question and tie it up in a nice little bow, two commenters in the errata mentioned that the before picture for this scenario is actually the recommended way to implement cross-field validations.
While it's certainly a design smell emanating from the windward direction of Spring MVC, it's not a problem with your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With