POST : @ModelAttribute not convert Map object of wrapper DTO

150 Views Asked by At

I need your help to solve a @ModelAttribute problem qith a java Map object.

Context

The following REST Controller expose a POST api that accept a wrapper dto.

@Validated
@RestController
@Slf4j
@RequestMapping(path = "/api/v1/modelattribute", produces = MediaType.APPLICATION_JSON_VALUE)
public class AController {

  @PostMapping(value = "wrapperdto", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
  public void testMapInWrapperDto(@ModelAttribute("wrapper") WrapperDto wrapper) {
    log.warn(wrapper.toString());
  }
@NoArgsConstructor
@AllArgsConstructor
@Data
public class WrapperDto {
  private String number;
  private Map<String, String> map = new HashMap<>();
}

Problem

When I call this api via swagger UI or via curl command spring responds with the following error

2023-03-31 09:01:55,666 [http-nio-8080-exec-10] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping         : Mapped to fr.gregoire.passpro.backend.aaaa.AController#testMapInWrapperDto(WrapperDto)
2023-03-31 09:01:55,666 [http-nio-8080-exec-10] DEBUG org.springframework.web.servlet.DispatcherServlet  : POST "/api/v1/modelattribute/wrapperdto", parameters={multipart}
2023-03-31 09:01:55,668 [http-nio-8080-exec-10] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping         : Mapped to fr.gregoire.passpro.backend.aaaa.AController#testMapInWrapperDto(WrapperDto)
2023-03-31 09:01:55,668 [http-nio-8080-exec-10] DEBUG org.springframework.web.method.HandlerMethod       : Could not resolve parameter [0] in public void fr.gregoire.passpro.backend.aaaa.AController.testMapInWrapperDto(fr.gregoire.passpro.backend.aaaa.WrapperDto): org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'wrapper' on field 'map': rejected value [{
  "cheese-burger": "280g",
  "classic-burger": "50g"
}]; codes [typeMismatch.wrapper.map,typeMismatch.map,typeMismatch.java.util.Map,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [wrapper.map,map]; arguments []; default message [map]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Map' for property 'map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map' for property 'map': no matching editors or conversion strategy found]
2023-03-31 09:01:55,669 [http-nio-8080-exec-10] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver    : Using @ExceptionHandler fr.gregoire.passpro.backend.resterror.RestExceptionHandler#handleException(Exception, WebRequest)
2023-03-31 09:01:55,669 [http-nio-8080-exec-10] DEBUG o.s.w.s.m.m.annotation.HttpEntityMethodProcessor   : Using 'application/octet-stream', given [*/*] and supported [*/*]
2023-03-31 09:01:55,669 [http-nio-8080-exec-10] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver    : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'wrapper' on field 'map': rejected value [{<EOL><EOL>  "cheese-burger": "280g",<EOL><EOL>  "classic-burger": "50g"<EOL><EOL>}]; codes [typeMismatch.wrapper.map,typeMismatch.map,typeMismatch.java.util.Map,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [wrapper.map,map]; arguments []; default message [map]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Map' for property 'map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map' for property 'map': no matching editors or conversion strategy found]]
2023-03-31 09:01:55,669 [http-nio-8080-exec-10] DEBUG org.springframework.web.servlet.DispatcherServlet  : Completed 400 BAD_REQUEST

The curl command executed :

curl -X 'POST' \
  'http://localhost:8080/api/v1/modelattribute/wrapperdto' \
  -H 'accept: */*' \
  -H 'Content-Type: multipart/form-data' \
  -F 'number=65431' \
  -F 'map={
  "cheese-burger": "280g",
  "classic-burger": "50g"
}'

Frameworks

  • spring boot : 2.7.7
  • springdoc-openapi-ui : 1.6.14 (=swagger-ui)
  • vuejs : 2.6.14
  • curl command
  • lombok

Question

How can I do to pass a Map object to this POST api ?

Thanks for your help
Nicolas

1

There are 1 best solutions below

0
Nicolas On

I try to set in one line the map in curl command

curl -X 'POST' \
  'http://localhost:8080/api/v1/modelattribute/wrapperdto' \
  -H 'accept: */*' \
  -H 'Content-Type: multipart/form-data' \
  -F 'number=sdfg' \
  -F 'map={"cheese-burger":"280g","classic-burger":"50g"}'

I also try to use Map<Object,Object> instead of Map<String,String> and sme style error :

@NoArgsConstructor
@AllArgsConstructor
@Data
public class WrapperDto {
  private String number;
  private Map<Object, Object> map;
}