5

I have a simple validator to validate that a String value is part of a predefined list:

public class CoBoundedStringConstraints implements ConstraintValidator<CoBoundedString, String>
{

private List<String> m_boundedTo;

@Override
public void initialize(CoBoundedString annotation)
{
    m_boundedTo = FunctorUtils.transform(annotation.value(), new ToLowerCase());
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context)
{
    if (value == null )
    {
        return true; 
    }

    context.disableDefaultConstraintViolation();
    context.buildConstraintViolationWithTemplate("should be one of " + m_boundedTo).addConstraintViolation();
    return m_boundedTo.contains(value.toLowerCase());
}

}

For example it will Validate:

@CoBoundedString({"a","b" })
public String operations;

I want to create a validator For a list of Strings to validate something like this:

@CoBoundedString({"a","b" })
public List<String> operations = new ArrayList<String>();

I tried this:

public class CoBoundedStringListConstraints implements ConstraintValidator<CoBoundedString, List<String>>
{

private CoBoundedString m_annotation;

@Override
public void initialize(CoBoundedString annotation)
{
    m_annotation = annotation;
}

@Override
public boolean isValid(List<String> value, ConstraintValidatorContext context)
{
    if (value == null )
    {
        return true; 
    }

    CoBoundedStringConstraints constraints = new CoBoundedStringConstraints();
    constraints.initialize(m_annotation);
    for (String string : value)
    {
        if (!constraints.isValid(string, context))
        {
            return false;
        }
    }
    return true;
}

}

The problem is, if list contains 2 or more illeagal values, there will be only one (the first one) constraint violation. I want it to have more than one. How should I do that?

1

1 Answer 1

5

There are 2 problems with your current code:

In your CoBoundedStringListConstraints's isValid method you should iterate over all elements of the given list like this (set a allValid flag appropriate):

@Override
public boolean isValid(List<String> value,
        ConstraintValidatorContext context) {
    if (value == null) {
        return true;
    }

    boolean allValid = true;
    CoBoundedStringConstraints constraints = new CoBoundedStringConstraints();
    constraints.initialize(m_annotation);
    for (String string : value) {
        if (!constraints.isValid(string, context)) {
            allValid = false;
        }
    }
    return allValid;
}

The second is the implementation of equals for the constraint violation (javax.validation.Validator.validate() returns a set!). When you are always putting in the same message (should be one of [a, b]), the set will still contain only 1 element. As a solution you could prepend the current value to the message (class CoBoundedStringConstraints):

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {

    if (value == null) {
        return true;
    }

    if (!m_boundedTo.contains(value)) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(
                value + " should be one of " + m_boundedTo)
                .addConstraintViolation();
        return false;
    }
    return true;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! it works! @Valid suppose to do what CoBoundedStringListConstraints does?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.