2

my problem is that I have a form which has html select element with some choosing option value & I want to validate those value using :

org.hibernate.validator.constraints
or
javax.validation.constraints

annotations. here is my select element:

<select name="status" id="tbSelect">
    <option value="ACTIVE">ACTIVE</option>
    <option value="LISTEN">LISTEN</option>
    <option value="DOWN">DOWN</option>
</select>

how I can for example validate the value of the options(DOWN,LISTEN,ACTIVE) inside the select element by using the annotation validators which I mention above?

my form is like this :

<form:form action="../agents/add" method="POST" commandName="myAgent">
     <form:select id="tbSelect" path="state">
            <form:option value="ACTIVE" path="state">ACTIVE</form:option>
            <form:option value="LISTEN" path="state">LISTEN</form:option>
            <form:option value="DOWN" path="state">DOWN</form:option>
    </form:select>

I have defined my controller method like this:

    @RequestMapping(value = "agents/add", method = RequestMethod.POST)
    public String addAgentSubmit(@ModelAttribute("myAgent") @Valid final AgentValidator agent, BindingResult result, RedirectAttributes redirect) {
      if (result.hasErrors()) {
        return "admin/agent/add";
      } 
       ...
    }

and I also define a ModelAttribute like this:

@ModelAttribute("myAgent")
 public AgentValidator getLoginForm() {
    return new AgentValidator();
 }

Here is my AgentValidator class also:

public class AgentValidator {
    @NotEmpty(message = "your state can not be empty !")
    private String state;
Mehdi
  • 3,795
  • 3
  • 36
  • 65

1 Answers1

2

Since your state field looks more like an enumeration, first of all I would recommend to change state field into enum, let Spring MVC to bind that field and use only @NotNull annotation:

public class AgentValidator {
    @NotNull(message = "your state can not be empty !")
    private AgenState state;

Where AgentState is:

public enum AgentState {
    DOWN,LISTEN,ACTIVE
}

But if for certain reasons you can't change your model, then you may use custom constraints.

Particular you need to create your annotation AgentStateConstraint:

@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = AgentStateConstraintValidator.class)
@Documented
public @interface AgentStateConstraint {

    String message() default "Some message";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

Then you need to create validator AgentStateConstraintValidator:

public class AgentStateConstraintValidator implements ConstraintValidator<AgentStateConstraint, String> {

    //Accepted values
    private static final Set<String> ACCEPTED_VALUES = new HashSet<String>(
            Arrays.asList(
                    "DOWN",
                    "LISTEN",
                    "ACTIVE"
            )
    );

    public void initialize(AgentStateConstraint constraintAnnotation) {
    }

    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        return ACCEPTED_VALUES.contains(object);
    }

}
n1ckolas
  • 4,380
  • 3
  • 37
  • 43
  • just one problem, when I inject a wrong value the validation works but with default error message:Failed to convert property value of type java.lang.String to required type tm.sys.validator.AgentState for property state; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @javax.validation.constraints.NotNull tm.sys.validator.AgentState for value ACTIVE3; nested exception is java.lang.IllegalArgumentException: No enum constant tm.sys.validator.AgentState.ACTIVE3 How 2 change the def message & put my own message ? – Mehdi Mar 17 '13 at 10:57
  • 1
    For handling this you need to either define `@ExceptionHandler` for `org.springframework.core.convert.ConversionFailedException` or specify your own conversion strategy with `@InitBinder`. But since user enters `status` through dropdown, I believe this things shouldn't happen at all. – n1ckolas Mar 17 '13 at 11:05
  • well, I provide this situation myself to avoid any possible attack because an attacker may provide this situation to break down your app! right ? I will check your solution & tell u the result soon ! thanx – Mehdi Mar 17 '13 at 11:09
  • 1
    Somebody can enter invalid values, but Spring MVC throws an exception before binding or actual handling invoking. Thus typically there is no big point to handle such cases, except if your are developing REST servers. So if you do need to handle incorrect conversion, 2 possible solutions I suggested in previous comment. Please take a look, f.e. in this [entry](http://stackoverflow.com/questions/4617099/spring-3-0-mvc-binding-enums-case-sensitive). – n1ckolas Mar 17 '13 at 12:21
  • dude I couldn't get it to work! when I provide the @ ExceptionHandler in my controller class I put a System.out.print but It never pass through there!
    I also try the @ InitBinder but the different methods in there confused me(because I don't know the sequence of program execution & I'm not a good debugger). I also look for DataBinder provided methods to overwrite the message string but I couldn't get it!
    – Mehdi Mar 18 '13 at 19:20
  • using typeMismatch.state solved my problem take a look at this: http://www.raistudies.com/spring/spring-mvc/form-processing-spring-mvc-3-annotation/ – Mehdi Mar 31 '13 at 05:44