MethodArgumentConversionNotSupportedException when I try to map json string onto java domain class in Spring controller's method
I think you need to specify that your GET mapping is looking to consume JSON:
@RequestMapping(value = "/get-templates", method = RequestMethod.GET, consumes = "application/json")
public List<Template> getTemplates(@RequestParam(required = false, name = "context") Context context) {
//...
}
If this doesn't work then you can call the Jackson ObjectMapper yourself:
@RequestMapping(value = "/get-templates", method = RequestMethod.GET)
public List<Template> getTemplates(@RequestParam(required = false, name = "context") String context) {
ObjectMapper mapper = new ObjectMapper();
Context myContext = mapper.readValue(context, Context.class);
//...
}
Cannot use Map as a JSON @RequestParam in Spring REST controller
Here is the solution that worked:
Just define a custom converter from String
to Map
as a @Component
. Then it will be registered automatically:
@Component
public class StringToMapConverter implements Converter<String, Map<String, String>> {
@Override
public Map<String, Object> convert(String source) {
try {
return new ObjectMapper().readValue(source, new TypeReference<Map<String, String>>() {});
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}
Meaning of parameters are transferred when backend receive the special character in springboot project
It seems it is getting URL encoded.
You could use URLDecoder.decode()
on what you receive.
Jquery serialize & @RequestBody not working
The HTTP 400 Bad Request
(The request sent by the client was syntactically incorrect) error occurs when the client did not send a syntactically correct entity.
In this case, the request body is expected to be a valid json, but it wasn't. As @Dave mentioned, your request does not contain a JSON, but a urlencoded string such as name=stack&value=overflow
. Instead, it should be a JSON, such as {"name":"stack", "value":"overflow"}
.
To achieve this, please refer to another good thread : Convert form data to JavaScript object with jQuery .
A possible fix of your code:
$("#add_more_contact").click(function(){
var formJson = $("#addContactForm").serializeToObject(); // use plugin, or build by yourself
// this variable should be a javascript object,
// such as {"name":"stack", "value":"overflow"}
$.ajax( {
url : "/myproject/admin/addContacts.htm",
type : "POST",
data : JSON.stringify(formJson), // serialize javascript object to JSON 'string'
dataType : "json", // 'text' -> 'json'
contentType : "application/json", // this can be omitted
success : ...,
error : ...,
});
});
Using Spring MVC Test to unit test multipart POST request
Since MockMvcRequestBuilders#fileUpload
is deprecated, you'll want to use MockMvcRequestBuilders#multipart(String, Object...)
which returns a MockMultipartHttpServletRequestBuilder
. Then chain a bunch of file(MockMultipartFile)
calls.
Here's a working example. Given a @Controller
@Controller
public class NewController {
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String saveAuto(
@RequestPart(value = "json") JsonPojo pojo,
@RequestParam(value = "some-random") String random,
@RequestParam(value = "data", required = false) List<MultipartFile> files) {
System.out.println(random);
System.out.println(pojo.getJson());
for (MultipartFile file : files) {
System.out.println(file.getOriginalFilename());
}
return "success";
}
static class JsonPojo {
private String json;
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
}
}
and a unit test
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Example {
@Autowired
private WebApplicationContext webApplicationContext;
@Test
public void test() throws Exception {
MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "{\"json\": \"someValue\"}".getBytes());
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders.multipart("/upload")
.file(firstFile)
.file(secondFile)
.file(jsonFile)
.param("some-random", "4"))
.andExpect(status().is(200))
.andExpect(content().string("success"));
}
}
And the @Configuration
class
@Configuration
@ComponentScan({ "test.controllers" })
@EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
}
The test should pass and give you output of
4 // from param
someValue // from json file
filename.txt // from first file
other-file-name.data // from second file
The thing to note is that you are sending the JSON just like any other multipart file, except with a different content type.
Decoding body parameters with Spring
You receive a string that contains a JSON content. You don't receive a JSON input as application/x-www-form-urlencoded
is used as content type and not application/json
as stated :
Your Action URL will receive a HTTP POST request, including a payload
body parameter, itself containing an application/x-www-form-urlencoded
JSON string.
So change the parameter type to String
and use Jackson or any JSON library to map the String
to your Action
class :
@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") String actionJSON) {
Action action = objectMapper.readValue(actionJSON, Action.class);
return ResponseEntity.status(HttpStatus.OK).build();
}
As pvpkiran suggests, you could have replaced @RequestParam
by @RequestBody
if you could pass the JSON string directly in the body of the POST request, and not as a value of a parameter but it seems that is not the case there.
Indeed by using @RequestBody
, the body of the request is passed through an HttpMessageConverter
to resolve the method argument.
To answer to your comment, Spring MVC doesn't provide a very simple way to achieve your requirement : mapping the String JSON to your Action
class.
But if you really need to automatize this conversion you have a lengthy alternative as stated in the Spring MVC documentation such as Formatters (emphasis is mine) :
Some annotated controller method arguments that represent String-based
request input — e.g.@RequestParam
,@RequestHeader
,@PathVariable
,
@MatrixVariable,
and@CookieValue
, may require type conversion if the
argument is declared as something other than String.For such cases type conversion is automatically applied based on the
configured converters. By default simple types such as int, long,
Date, etc. are supported. Type conversion can be customized through a
WebDataBinder, see DataBinder, or by registering Formatters with the
FormattingConversionService, see Spring Field Formatting.
By creating a formatter (FormatterRegistry
subclass) for your Action
class you could add that in the Spring web config as documented :
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ... add action formatter here
}
}
and use it in your parameter declaration :
public ResponseEntity action(@RequestParam("payload") @Action Action actionJ)
{...}
Related Topics
Spring Boot - How to Get Running Port and Ip Address
How to Pass Topics Dynamically to a Kafka Listener
Java - How to Find Students With Their Highest Marks Writing a Method in a Student Class
Crudrepository How to Find by Last Date Between
Iterating Over Two Arrays Simultaneously Using for Each Loop in Java
Comparing Two List by Using Java8 Matching Methods
Java Floating Point Number in Comma Instead of Dot
Calling Method That Exists in Child Classes But Not in Parent Class
Testing @Postconstruct With Mockito
How to Open Excel File Using JavaScript Code Without Using Activex Control
The Package Org.W3C.Dom Is Accessible from More Than One Module: <Unnamed>, Java.Xml
How to Subtract a Constant Value from All Elements of an Array
How to Open a .Dat File in Java Program
Lombok Is Not Generating Getter and Setter
Is There an Invisible Character That Is Not Regarded as Whitespace
Java.Lang.Noclassdeffounderror: Org/Springframework/Core/Env/Configurableenvironment