Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15542

BindingResult support for constructor argument mismatch on immutable data object

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 5.0 RC1
    • Fix Version/s: 5.0 RC4
    • Component/s: Web
    • Labels:
      None

      Description

      I've tried the the request data binding feature for immutable object. It's work fine. However binding error(such as type conversion error) can not handle using the BindingResult as follow:

      package com.example;
       
      import org.springframework.format.annotation.DateTimeFormat;
      import org.springframework.validation.BindingResult;
      import org.springframework.validation.annotation.Validated;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
       
      import javax.validation.constraints.NotNull;
      import java.time.LocalDate;
       
      @RestController
      public class ImmutableObjectRestController {
       
      	@GetMapping("/immutable")
      	Query search(@Validated Query query, BindingResult bindingResult) {
      		System.out.println(bindingResult);
      		return query;
      	}
       
      	public static class Query {
       
      		@NotNull private final String name;
      		private final String mail;
      		private final String tel;
      		private final LocalDate baseDate;
       
      		public Query(String name, String mail, String tel,
      				@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate baseDate) {
      			this.name = name;
      			this.mail = mail;
      			this.tel = tel;
      			this.baseDate = baseDate;
      		}
       
      		public String getName() {
      			return name;
      		}
       
      		public String getMail() {
      			return mail;
      		}
       
      		public String getTel() {
      			return tel;
      		}
       
      		public LocalDate getBaseDate() {
      			return baseDate;
      		}
       
      	}
       
      }
      

      A validation error(e.g. name parameter is null) can handle above implementation.

      $ curl -D - http://localhost:8080/[email protected]\&tel=09012345678\&baseDate=2017-08-01
      

      print on console as follow:

      org.springframework.validation.BeanPropertyBindingResult: 1 errors
      Field error in object 'query' on field 'name': rejected value [null]; codes [NotNull.query.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [query.name,name]; arguments
      

      However a binding error(e.g. baseDate parameter is nonexistence date) can not handle above implementation.

      $ curl -D - http://localhost:8080/[email protected]\&tel=09012345678\&baseDate=2017-08-32
      HTTP/1.1 400 
      Content-Type: application/json;charset=UTF-8
      Transfer-Encoding: chunked
      Date: Sun, 14 May 2017 11:20:29 GMT
      Connection: close
       
      {"timestamp":"2017-05-14T11:20:29.495+0000","status":400,"error":"Bad Request","message":"Failed to convert value of type 'java.lang.String[]' to required type 'java.time.LocalDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate] for value '2017-08-32'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2017-08-32]","path":"/immutable"}
      

      Is specification this behavior ?

        Issue Links

          Activity

          Hide
          juergen.hoeller Juergen Hoeller added a comment -

          The problem there is that we can't even construct the parameter object in such a case, since such validation fails at constructor argument level. We'd have to pass in null for the Query object in your case, exposing just a BindingResult for it. I'll revisit this for RC2.

          Show
          juergen.hoeller Juergen Hoeller added a comment - The problem there is that we can't even construct the parameter object in such a case, since such validation fails at constructor argument level. We'd have to pass in null for the Query object in your case, exposing just a BindingResult for it. I'll revisit this for RC2.
          Hide
          juergen.hoeller Juergen Hoeller added a comment -

          We're explicitly handling a constructor argument resolution mismatch as binding failure now, manually registering FieldErrors for such arguments and exposing them the same way as bean property binding exceptions or post-construction validation exceptions.

          Show
          juergen.hoeller Juergen Hoeller added a comment - We're explicitly handling a constructor argument resolution mismatch as binding failure now, manually registering FieldErrors for such arguments and exposing them the same way as bean property binding exceptions or post-construction validation exceptions.

            People

            • Assignee:
              juergen.hoeller Juergen Hoeller
              Reporter:
              kazuki43zoo Kazuki Shimizu
              Last updater:
              St├ęphane Nicoll
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                5 weeks, 1 day ago