4

I am using the Oval validation framework to validate fields that HTML fields cannot hold malicious javascript code. For the malicious code detection, I am using an external framework that returns me a list of errors that I would like to use as error messages on the field. The problem I am running into is that I can only setMessage in the check implementation, while I would rather do something like setMessages(List). So while I am currently just joining the errors with a comma, I would rather pass them back up as a list.

Annotation

@Target({ ElementType.METHOD, ElementType.FIELD})
@Retention( RetentionPolicy.RUNTIME)
@Constraint(checkWith = HtmlFieldValidator.class)
public @interface HtmlField {
   String message() default "HTML could not be validated";
}

Check

public class HtmlFieldValidator  extends AbstractAnnotationCheck<HtmlDefaultValue> {
    public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
        if (o1 == null) {
            return true;
        } else {
            CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
            if (cleanResults.getErrorMessages().size() > 0) {
                String errors = StringUtils.join(cleanResults.getErrorMessages(), ", ");
                this.setMessage(errors);
                return false;
            } else {
                return true;
            }
        }
    }
}

Model class

class Foo {

    @HtmlField
    public String bar;

}

Controller code

Validator validator = new Validator(); // use the OVal validator
Foo foo = new Foo();
foo.bar = "<script>hack()</script>";

List<ConstraintViolation> violations = validator.validate(bo);

if (violations.size() > 0) {
    // inform the user that I cannot accept the string because 
    // it contains invalid html, using error messages from OVal
}
Jonas
  • 121,568
  • 97
  • 310
  • 388
Ransom Briggs
  • 3,025
  • 3
  • 32
  • 46

2 Answers2

4

If setMessage(String message) is a method created by a superclass, you can override it and once it receives the data, simply split the string into a list and call a second function in which you would actually place your code. On a side note, I would also recommend changing the separating string to something more unique as the error message itself could include a comma.

Your question doesn't really make much sense though. If you are "passing them back up" to a method implemented in a superclass, then this voids the entire point of your question as the superclass will be handling the data.

I am going to assume the setError methods is a simple setter that sets a String variable to store an error message that you plan to access after checking the data. Since you want to have the data in your preferred type, just create a new array of strings in your class and ignore the superclass. You can even use both if you so desire.

public class HtmlFieldValidator  extends AbstractAnnotationCheck<HtmlDefaultValue> {
    public String[] errorMessages = null;

    public void setErrorMessages(String[] s) {
        this.errorMessages = s;
    }

    public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
        if (o1 == null) {
            return true;
        } else {
            CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
            if (cleanResults.getErrorMessages().size() > 0) {
                //String errors = StringUtils.join(cleanResults.getErrorMessages(), ", ");
                //this.setMessage(errors);
                this.setErrorMessages(cleanResults.getErrorMessages());
                return false;
            } else {
                return true;
            }
        }
    }
}

Elsewhere:

HtmlFieldValidator<DefaultValue> hfv = new HtmlFieldValidator<DefaultValue>();
boolean satisfied = hfv.isSatisfied(params);
if (!satisfied) {
    String[] errorMessages = hfv.errorMessages;
    //instead of using their error message

    satisfy(errorMessages);//or whatever you want to do
}

EDIT:

After you updated your code I see what you mean. While I think this is sort of overdoing it and it would be much easier to just convert the string into an array later, you might be able to do it by creating a new class that extends Validator its setMessage method. In the method, you would call super.setMethod as well as splitting and storing the string as an array in its class.

class ValidatorWithArray extends Validator {
    public String[] errors;
    public final static String SPLIT_REGEX = ";&spLit;";// Something unique so you wont accidentally have it in the error

    public void setMessage(String error) {
        super.setMessage(error);
        this.errors = String.split(error, SPLIT_REGEX);
    }
}

In HtmlFieldValidator:

public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
            if (o1 == null) {
                return true;
            } else {
                CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
                if (cleanResults.getErrorMessages().size() > 0) {
                    String errors = StringUtils.join(cleanResults.getErrorMessages(), ValidatorWithArray.SPLIT_REGEX);
                    this.setMessage(errors);
                    return false;
                } else {
                    return true;
                }
            }
        }

And now just use ValidatorWithArray instead of Validator

Stas Jaro
  • 4,747
  • 5
  • 31
  • 53
  • While the code you provided would be good if I controlled the validation framework, it does not integrate with the validation framework I am using (OVal). There is a lot of other validation that is going on that I would like this to seamlessly work with with. I also added some extra code to try and show what I meant by "passing them back up". – Ransom Briggs Oct 23 '12 at 14:50
0

The situation in which I want to achieve this was different from yours, however what I found was best in my case was to create an annotation for each error (rather than having one that would return multiple errors). I guess it depends on how many errors you are likely to be producing in my case it was only two or three.

This method makes also makes your code really easy to reuse as you can just add the annotations wherenever you need them and combine them at will.

Stuart Clark
  • 611
  • 8
  • 13