Spring 4 MVC Validation not working - BindingResult hasErrors is false

13,200

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>
Share:
13,200
PDStat
Author by

PDStat

Updated on June 28, 2022

Comments

  • PDStat
    PDStat almost 2 years

    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>
    
  • Neo
    Neo over 9 years
    I got the same problem. I found that if validation error happened, the @Controller method did not execute at all