views:

509

answers:

5

I'm not really sure if it's a good design decision to make the validators validate commands based on the state of the database. For example if I need to validate a User bean besides checking if the email and username are empty etc. I also need to reject values if they are already used. Should this kind of logic go in the validators or the service objects?

+5  A: 

Well your validators are just spring beans, right, so they can be injected with the service objects that handle data access. You can have your validators get data from the database without compromising the design.

skaffman
+1  A: 

no, IMHO validators should be small and side-effect free in order to allow them to be easily combined. Definitively a validator should be decoupled from persistence layer.

dfa
What do you do when you want to check that a reference refers to a real entity? They shouldn't change the data, but sometimes you need to do a least an id verification.
Kathy Van Stone
I've heard or read this before, that's exactly why I'm asking the question. But I'm not really sure what I'm supposed to do if I don't make them able to read from a database (without side effects). I'm kinda confused in this topic because it seems like a lot of people in the Java world share your opinion, while in Django and RoR it's perfectly normal to tie validation to the database.
Vasil
A: 

I checked one of mine and I'm calling the service layer from the validator:

@Service
public final class StartFormValidator {
private FacilityService facilityService;
private AdminService adminService;

/**
 * Verify that they've selected a facility. Verify that they've selected a
 * valid facility. Verify that they've selected a view and that it's a valid
 * view.
 * 
 * @param startForm
 * @param errors
 * @return true if no errors were set
 */
public boolean isValid(final StartForm startForm, final Errors errors) {
    if (startForm.getFacilityId() == 0) {
        errors.rejectValue("facilityId", "facilityIdEmpty",
                "Select a facility.");
    }

    if (!this.facilityService.isFacilWaitlistEnabled(startForm
            .getFacilityId())) {
        errors.rejectValue("facilityId", "facilityInvalid",
                "Invalid facility");
    }

    if (StringUtils.isBlank(startForm.getPassword())) {
        errors.rejectValue("password", "passwordEmpty",
                "Enter the password.");

        return (false);
    }

    if (!this.adminService.validateAdmin(startForm.getPassword()))
        errors.rejectValue("password", "passwordInvalid",
                "Incorrect password");

    return (!errors.hasErrors());
}

/**
 * @param _facilityService
 */
@Autowired
public void setFacilityService(final FacilityService _facilityService) {
    this.facilityService = _facilityService;
}

/**
 * @param _adminService
 */
@Autowired
public void setAdminService(final AdminService _adminService) {
    this.adminService = _adminService;
}

}

lumpynose
+2  A: 

That would very much depend on how you define validation. Consider this: You're buying something, and you enter your credit card number. If the check digit does not match, you have failed validation. No transaction has been attempted. If however, it is a valid credit card number, but it does not match your post code (DB/third party interaction required), then that is a payment error.

Now consider this: You are entering your address, and you enter Mastiffica as your country. Why did the system even allow you to enter this - they should have restricted the interface to valid entries only (No DB needed post entry).

Or you enter "fifty" in the amount field of your bank payment screen. Why does it allow letters there - that fails validation (No need for DB). But you then enter 50 in the amount field, and it turns out you don't have fifty pounds in your account. Is that a validation error? Or is it a failed transaction?

Now, consider you have passed all basic entry validations (credit card checksum, country, digits, post code) and the transaction fails, because your credit card has expired. Is that validation error, or a failed transaction?

You can think of validation as a basic guarantee that users won't enter completely wild data, or you can think of validation as "I can complete this transaction with the data I have been given". I would personally favor the former, but again, it's matter of definition.

Then there's the aspect of first line validation as a security measure - wild data that has been accepted past your top UI layer can be a security risk (SQL injection, e.g.)

George
A: 

If you really believe in "MVC" then I don't think so, that you would want your validators to go to database.Validation is a phase which essentially validates the data from a business logic point of view.

Database doesn't need to be aware of how validators will use it, nor should validators should be aware of what database is like. That just doesn't fit in MVC model. Tomorrow if you have data coming from multiple sources, would you still go ahead and tell your validators that which source in specific it should access under what conditions. That itself will constitute logic which is not even req. in application.

The kind of validation you are looking for will be taken up as part of business objects which would ensure that before the service objects are even called; such a combination doesn't already exist.

Service objects should also not contain business validations, so neither it belongs in validators nor in Service objects. But yes, if the application is small enough to not worry about too many layers a skewed approach is fine but only as long as "it is followed as a standard throughout".

In short, I feel spring validators are meant for basic validations and not really business validations.

Priyank