Issue
I am trying to send a JSON object to a Spring controller, the controller takes in a request body as a Map<String, Object>
, the JSON itself is correct and sending the same JSON over postman works properly as well, it's just when I send it using the HttpClient.
Here is the JSON I am trying to send over:
{"fruit": "Apple", "color": "Red"}
My HTTP request:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String jsonString = mapper.writeValueAsString(body);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("content-type", "application/json")
.POST(BodyPublishers.ofString(jsonString))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
My controller:
@PostMapping(value = "/config/addDocument", consumes = {"application/json"})
public void addDocument(@RequestBody Map<String, Object> document)
I get this error:
HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"fruit": "Apple", "color": "Red"}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"fruit": "Apple", "color": "Red"}')<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 1]]
I tried to use postman to send the same request and it works fine, creating a variable string and sending that over works fine as well, what am I doing wrong regarding the request?
Edit
The client is from the java.net.http.HttpClient
package.
I created the client using HttpClient.newHttpClient()
I am using the Spring Boot Starter Web 2.7.5.
Edit 2
Based on the answer I tried switching the input JSON string into a map and converting the map back to a JSON string and sending that and that worked.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(body, Map.class);
String jsonString = mapper.writeValueAsString(map);
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonString))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
Solution
I tried below code with Spring Boot 2.7.5, Java 17. Driver Code for sending request.
Map<String, String> body = new LinkedHashMap<>(); //new HashMap() is also fine here
body.put("fruit", "Apple");
body.put("color", "Red");
//Map.of("fruit", "Apple", "color", "Red");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String jsonString = mapper.writeValueAsString(body);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://localhost:8080/test"))
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonString))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Status Code : " + response.statusCode());
System.out.println("Headers : " + response.headers());
The rest controller is same as you mentioned in the question. If I instantiate the map using Map.of()
still its is working fine.
The last sysout statements outputs to console as below.
Answered By - KunalVarpe
Answer Checked By - Cary Denson (JavaFixing Admin)