Spring 4 MVC Validation not working - BindingResult hasErrors is false

PDStat picture PDStat · Nov 18, 2014 · Viewed 12.5k times · Source

I am unit testing a Spring controllers post method (using org.springframework.test.web.servlet.MockMvc), and I'm trying to confirm that when there are validation errors in the form it will send the view back to the form by checking the BindingResult.hasErrors method.

Here is my test

  @Test
  public void testFilterChannelProgrammesWhenChannelListAndGenreListAreEmptyAndProgNameIsTooLong() throws Exception {
    String progName = TestUtil.createStringWithLength(301);

    mockMvc.perform(post("/api/filter")
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .param("progName", progName)
        .sessionAttr("filter", new ProgrammeSearchDTO())
        )
        .andExpect(status().isOk())
        .andExpect(view().name("api/filter"))
        .andExpect(forwardedUrl("/WEB-INF/jsp/api/filter.jsp"))
        .andExpect(model().attributeHasFieldErrors("filter", "progName"))
        .andExpect(model().attributeHasFieldErrors("filter", "genreIdList"))
        .andExpect(model().attributeHasFieldErrors("filter", "channelIdList"))        
        .andExpect(model().attribute("filter", hasProperty("progName", is(progName))));

    verifyZeroInteractions(channelProgrammeServiceMock);
  }

Here is the DTO that the session attribute is bound to

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

public class ProgrammeSearchDTO {

  @NotEmpty
  private String[] channelIdList;

  @NotEmpty
  private String[] genreIdList;

  private String fromDateTime;
  private String toDateTime;

  @Length(max = 200)
  private String progName;

  private boolean subtitled;
  private boolean signed;
  private boolean film;

  public String[] getChannelIdList() {
    return channelIdList;
  }

  public String getFromDateTime() {
    return fromDateTime;
  }

  public String[] getGenreIdList() {
    return genreIdList;
  }  

  public String getProgName() {
    return progName;
  }

  public String getToDateTime() {
    return toDateTime;
  }

  public boolean isFilm() {
    return film;
  }

  public boolean isSigned() {
    return signed;
  }

  public boolean isSubtitled() {
    return subtitled;
  }

  public void setChannelIdList(String[] channelIdList) {
    this.channelIdList = channelIdList;
  }

  public void setFilm(boolean film) {
    this.film = film;
  }

  public void setFromDateTime(String fromDateTime) {
    this.fromDateTime = fromDateTime;
  }

  public void setGenreIdList(String[] genreIdList) {
    this.genreIdList = genreIdList;
  }

  public void setProgName(String progName) {
    this.progName = progName;
  }

  public void setSigned(boolean signed) {
    this.signed = signed;
  }

  public void setSubtitled(boolean subtitled) {
    this.subtitled = subtitled;
  }

  public void setToDateTime(String toDateTime) {
    this.toDateTime = toDateTime;
  }  


}

And the controller method

  @RequestMapping(value = "/api/filter", method = RequestMethod.POST)
  public String filterChannelProgrammes(@Valid @ModelAttribute ProgrammeSearchDTO programmeSearchDTO, BindingResult result, Model model) {
    if(result.hasErrors()) {
      return "api/filter";
    }
    model.addAttribute("results", null);
    return "redirect:filterResults";
  }

For this test the return "api/filter"; should be actioned, but hasErrors() is always false. I have also tried with the following

  @RequestMapping(value = "/api/filter", method = RequestMethod.POST)
  public String filterChannelProgrammes(@Valid @ModelAttribute("filter") ProgrammeSearchDTO programmeSearchDTO, BindingResult result, Model model) {
    if(result.hasErrors()) {
      return "api/filter";
    }
    model.addAttribute("results", null);
    return "redirect:filterResults";
  }

But hasErrors() is still false

EDIT

After some more digging I have this sorted, it also required the following in the context config xml

<mvc:annotation-driven />

<bean id="validator"
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

And these dependencies in the maven pom.xml

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.2.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>2.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.4</version>
    </dependency>

Answer

PDStat picture PDStat · Nov 20, 2014

After some more digging I have this sorted, it also required the following in the context config xml

<mvc:annotation-driven />

<bean id="validator"
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

And these dependencies in the maven pom.xml

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.2.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>2.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.4</version>
    </dependency>