views:

109

answers:

5

What is the best way to validate input? For argument's sake, if the input is invalid, the user would like a message explaining why.

Here is what I can come up with.

  • Validator method: Pass input to the validator, which returns true if the input is valid. Otherwise, the validator either returns false (or an error code) and lets the caller handle the invalid input. Or the validator takes the responsibility of taking action itself. Or the validator calls a callback method. Drawbacks: the steps taken to validate might be repeated when the actual method is called.

  • Pass the input directly to the method, without validation. Let the method handle invalid messages itself. It can either send the error message to the user directly or use a callback method. After sending the message, the method must return or throw an exception to stop processing the invalid input. The calling class will continue to the next line of input. Drawbacks: this method now has a side effect of sending an error message.

What is the appropriate strategy here? Note that I do not believe throwing exceptions is appropriate because handling invalid input is a core function of the application, at least in my case.

A: 

Maybe look at the Command Pattern and put the validation logic in the invoker class.

Nick Miller
A: 

You shouldn't pass the input directly to the method (I guess that by "the method" you mean some business logic) to be honest as it couples the view and the model. What you should do is to make either a controller with a validation method or a separate validation class which would take the input and validate it using some "external" methods. Then depending on the result the controller/validator can either return a validation error or forward the input wherever you want. The biggest benefit of this as I said earlier is the decoupling of the model and the view. The model shouldn't really know anything about the view (what if you want to change the view? you'll have to rewrite your model!). I'm not really sure why would you want to duplicate the validation code in the business model? Validation and navigation should be what a controller does. At least that's how the MVC pattern does things.
Also throwing exceptions isn't that bad but they should be thrown in the model and caught in the controller. For example you have a system where you want users to have unique logins, the user inputs a login that is already in the DB, the controller calls a validation method which tries to (using the model) insert it in the DB. If it all goes well then it is inserted and the controller can return a "you inserted a value successfuly" message. But if the model throws an exception (like Unique Constraint Violation error or something) then the controller should simply catch it and return "this login already exists in the DB". This way the model knows nothing about the view and is reusable and you have no code duplication.

Zenzen
+2  A: 

Have a look at Spring's data binding and validation framework. Very nice indeed, and designed to be usable either on its own or as part of a UI.

duffymo
A: 

public interface Validator {

/**
 * Validates a JComponent</code>.
 * @param component
 *       The component to validate.
 * @param message
 *       The message to display if the validation fails.
 * @return
 *       Returns <code>false</code> if the validation fails, and
 *       <code>true</code> otherwise.
 */
boolean validate(JComponent component, String message);

}

You could have an AbstractValidator(Extends javax.swing.InputVerifier) class that does handles message display next to the JComponent with an invalid entry. Have a look at this example

walters
A: 

Hi, now I'm using Hibernate validator framework, very simple and usefull:

I annotate classes with what I need and then use it:

My entity class:

public class Content {

@NotNull
private Heading heading;

@NotNull
@Length(max = 8)
private String contentType;

    // Everything else

}

My Validator Component:

@Component
public class Validator implements IValidator {
    protected static Log log = LogFactory.getLog(Validator.class);

    javax.validation.Validator validator;

    @Autowired 
    WebApplicationExceptionBuilder webApplicationExceptionBuilder;

    public void validate (Object entity) throws WebApplicationException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(entity);
        if (!violations.isEmpty()) {
            webApplicationExceptionBuilder
                        .raise("some fields are missing or incorrect", 
                            violations);
        }
    }

}

Where to use it:

public class Foo{

    @Autowired
    private IValidator validator;

    @Autowired
    private IContentService contentService;

    public void bar(Content c) throws Exception{
        validator.validate(c);
        contentService.persist(content);
    }

}
Davide