Trying to use Spring Boot REST to Read JSON String from POST
Solution 1
I think the simplest/handy way to consuming JSON is using a Java class that resembles your JSON: https://stackoverflow.com/a/6019761
But if you can't use a Java class you can use one of these two solutions.
Solution 1: you can do it receiving a Map<String, Object>
from your controller:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object> payload)
throws Exception {
System.out.println(payload);
}
Using your request:
curl -H "Accept: application/json" -H "Content-type: application/json" \
-X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
Solution 2: otherwise you can get the POST payload as a String
:
@RequestMapping(
value = "/process",
method = RequestMethod.POST,
consumes = "text/plain")
public void process(@RequestBody String payload) throws Exception {
System.out.println(payload);
}
Then parse the string as you want. Note that must be specified consumes = "text/plain"
on your controller.
In this case you must change your request with Content-type: text/plain
:
curl -H "Accept: application/json" -H "Content-type: text/plain" -X POST \
-d '{"name":"value"}' http://localhost:8080/myservice/process
Solution 2
To receive arbitrary Json in Spring-Boot, you can simply use Jackson's JsonNode
. The appropriate converter is automatically configured.
@PostMapping(value="/process")
public void process(@RequestBody com.fasterxml.jackson.databind.JsonNode payload) {
System.out.println(payload);
}
Solution 3
To add on to Andrea's solution, if you are passing an array of JSONs for instance
[
{"name":"value"},
{"name":"value2"}
]
Then you will need to set up the Spring Boot Controller like so:
@RequestMapping(
value = "/process",
method = RequestMethod.POST)
public void process(@RequestBody Map<String, Object>[] payload)
throws Exception {
System.out.println(payload);
}
Solution 4
To further work with array of maps, the followings could help:
@RequestMapping(value = "/process", method = RequestMethod.POST, headers = "Accept=application/json")
public void setLead(@RequestBody Collection<? extends Map<String, Object>> payload) throws Exception {
List<Map<String,Object>> maps = new ArrayList<Map<String,Object>>();
maps.addAll(payload);
}
Solution 5
The issue appears with parsing the JSON from request body, tipical for an invalid JSON. If you're using curl on windows, try escaping the json like -d "{"name":"value"}"
or even -d "{"""name""":"value"""}"
On the other hand you can ommit the content-type header in which case whetewer is sent will be converted to your String argument
Related videos on Youtube
PacificNW_Lover
Updated on October 02, 2021Comments
-
PacificNW_Lover over 2 years
Am using the latest version of Spring Boot to read in a sample JSON via Restful Web Service...
Here's my pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId> <artifactId>myservice</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.2.RELEASE</version> </parent> <properties> <java.version>1.7</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-rest-webmvc</artifactId> </dependency> <dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/libs-release</url> </repository> <repository> <id>org.jboss.repository.releases</id> <name>JBoss Maven Release Repository</name> <url>https://repository.jboss.org/nexus/content/repositories/releases</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/libs-release</url> </pluginRepository> </pluginRepositories> </project>
Here's my web service code:
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/myservice") public class BaseService { @RequestMapping(value="/process", method = RequestMethod.POST) public void process(@RequestBody String payload) throws Exception { System.out.println(payload); } }
When I invoke it using the following command:
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"name":"value"}' http://localhost:8080/myservice/process
I get this error message:
{"timestamp":1427515733546,"status":400, "error":"Bad Request", "exception": "org.springframework.http.converter.HttpMessageNotReadableException"," message": "Could not read JSON: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: java.io.PushbackInputStream@8252f; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: java.io.PushbackInputStream@8252f; line: 1, column: 1]", "path":"/myservice/process"
The only thing I am trying to do is pass in some valid JSON (as a string via curl) and to see if the String payload enters the process method as {"name":"value"}
What am I possibly doing wrong?
Thank you for taking the time to read this...
-
Andrea about 9 yearsYou have an error in your
pom.xml
: an useless/unclosed tag<dependency>
before<dependencies>
. But is not that your problem...
-
-
PacificNW_Lover about 9 yearsThanks Master Slave, the reason I didn't use a POJO is because this service is going to receive different types of JSON (containing different content)... Do you understand what I am trying to ask?
-
Master Slave about 9 yearsI understand (now). On the other hand, your server side is in fact OK. Its complaining about not being able to parse json, editing an answer
-
PacificNW_Lover about 9 yearsI am using bash from OS X Mavericks... What I am trying to do is pass in a JSON so I can parse it to return a custom response whether its valid or not. This is the first step is to first get a JSON string from the Post. Am I doing it wrong?
-
Master Slave about 9 yearsmhm, well, if I understand you correctly, not really. The fact that you send a content-type header set to application/json means that the conversion will be attempted before the request reaches handler method, and for invalid json this will fail with bad request 400. But, what you should do is send without the content-type header, than the request will reach your method, and there you can programatically try the conversion and return the appropriate response. Not sure if this is a viable approach for you, but its one that we'll work for sure
-
PacificNW_Lover about 9 yearswithout the content type it returned this: %7B%22name%22%3A%22value%22%7D=
-
PacificNW_Lover about 9 yearsThis worked! I just tried your second solution... Thank you very much. The issue is that this service is going to have different JSON coming in all the time and it doesn't have a schema... Would Map<String, Object> and also String payload be able to accommodate any type of JSON correctly?
-
Andrea about 9 years@socal_javaguy The first solution will parse any JSON for you into a
Map
object. If you are using the second solution will be your care to validate and parse the string to a JSON, for example using this: baeldung.com/jackson-json-to-jsonnode -
vishal sundararajan over 3 yearsI'm getting 404 error when the JSON contains Long data type stackoverflow.com/questions/64382824/…
-
Joao Moreno over 3 yearslike a charm! tks
-
Riberto Junior about 2 yearsI have a similar controller, but got another problem I got undefined chars when the string comes with special characters like ç ou õ, tried to set the charset with consumes = "text/plain; charset=utf-8", but no luck. Anyone?
-
Luís Cunha about 2 yearsI'm getting this error with this approach: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.fasterxml.jackson.databind.JsonNode]: Is it an abstract class?; nested exception is java.lang.InstantiationException at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:215) ~[spring-beans-5.3.18.jar:5.3.18] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Do you know what could be the problem?
-
LiberiFatali about 2 years@LuísCunha I just make a simple example and this works. Could you post your code?