1

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());
3
  • What is the Spring Boot version are you using? The HttpClient which you are using is Java htttp2 client? Please provide more details. Commented Nov 13, 2022 at 16:54
  • I don't think the issue is with the Spring Boot, cause it is working as expected on the 2.7.5 version through the postman as well as the HttpClient. I suspect the issue is with how you are passing the body object to ObjectMapper. Spring boot works file with the request body for map which is type of HashMap or LinkedHashMap. Also let me know which java version you have with spring boot it should be Java 11 or greater. Commented Nov 13, 2022 at 17:37
  • 1
    That is my question, for whatever reason serializing an object to JSON does not work and spring can't parse it, although you can see from the error that it got it right but for whatever reason it cannot parse it, I am using Java 17 Commented Nov 13, 2022 at 17:39

1 Answer 1

1

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.

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

@Yoh We can discuss further more of if required.
Huh, weird. I took the object provided and converted it into a map using mapper.readValue() and then back to string similar to what you did and now it works. Any idea why this is happening? Is there a way to avoid converting the given object twice? I'll update the question with my current code.
I accepted the answer, thanks for your efforts, do you have any idea why this is the case? It's definitely weird, especially that if I put a string in a variable and send that it works fine.
If possible can you also provide the little bit information about the body variable used in the code. What is type of it?? I will take a look at it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.