10

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 {
    ...
}

Refactoring

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?

PaddyC
  • 576
  • 7
  • 14
  • This question validates the 'before' picture above as the recommended way to implement cross-field valdations (http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303). I guess I might be best to leave as is – PaddyC Mar 05 '12 at 21:37
  • There's already a really good stack post with this: http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303 – Timothy Perez Mar 14 '12 at 16:35

2 Answers2

3

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.

Hartz Peter
  • 119
  • 6
2

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.

Community
  • 1
  • 1
MrGomez
  • 23,788
  • 45
  • 72