I am very new for spring mvc and java. i want to return a json data instead of string
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String getFoosAsJsonFromREST() {
return "{\"name\":\"MyNode\", \"width\":200, \"height\":100}";
}
actual output:
"{\"name\":\"MyNode\", \"width\":200, \"height\":100}"
output i want:
{"name":"MyNode", "width":200, "height":100}
i followed the link but i still can't get literal json output
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public JsonNode getFoosAsJsonFromREST() {
String everything = "{\"a\":2,\"b\":\"astring\",\"c\":6}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(everything);
return node;
}
output
{
"result": false,
"message": "Unexpected end-of-String when base64 content\n at [Source: N/A; line: -1, column: -1]"
}
You're nearly there :)
JSON is just an object format so you must return an object with key:value pairs.
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public MyJSONRespone getFoosAsJsonFromREST() {
MyJSONRespone myResponse = new MyJSONRespone();
myResponse.setName("MyNode");
myResponse.setWidth(200);
myResponse.setHeight(100);
return myResponse;
}
class MyJSONRespone{
private String name;
private Integer width;
private Integer Height;
//setters and getters
}
Also make sure you have the correct dependency in your POM if you are using Maven:
<!-- Jackson/JSON START -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
</dependency>
<!-- Jackson/JSON END -->
Sure you can return json output without your own class. First approach same as yours try this one https://stackoverflow.com/a/64482663/10353679
#RequestMapping(value = "/ex/fooss", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public ResponseEntity<JsonNode> getDeneme() {
String everything = "{\"name\":\"MyNode\", \"width\":200, \"height\":100}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(everything);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return ResponseEntity.ok(node);
}
The example above should work
Second approach in your code just return node.toString() with produces = "application/json". json is just format. Client will probably just check the Content-Type which is application/json and if the format of json is correct, Client's parser will just parse it.
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String getDeneme() {
String everything = "{\"a\":2,\"b\":\"astring\",\"c\":6}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(everything);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return node.toString();
}
IMPORTANT: node.toString(); might return NullPointerException since node can be null you should properly handle it.
And the other point is you should not create new ObjectMapper every time. You should inject ObjectMapper to this Controller class as a field and then just use injected objectMapper
Related
I have a RestController and when I call the method:
#RequestMapping(value = "/sigla/{sigla}")
#ResponseBody
public PaisDTO obterPorSigla(#PathVariable String sigla) {
return service.obterPorSigla(sigla);
}
If a record is found, I get a good JSON response:
{"nome":"Brasil","sigla":"BR","quantidadeEstados":27}
but when nothing is found on database the RestController returns null and I get a empty response, completely blank body.
How can I display a empty JSON instead of a blank response? Like bellow:
{}
Complete Controller:
#RestController
#RequestMapping("/pais")
public class PaisController {
#Autowired
private PaisService service;
#RequestMapping
public ResponseEntity<List<PaisDTO>> obterTodos() {
return CreateResponseEntity.getResponseEntity(service.obterTodos());
}
#RequestMapping(value = "/sigla/{sigla}", method = RequestMethod.GET, consumes="application/json", produces="application/json")
public ResponseEntity<PaisDTO> obterPorSigla(#PathVariable String sigla) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
PaisDTO paisDTO = service.obterPorSigla(sigla);
if(paisDTO != null) return new ResponseEntity<PaisDTO>(paisDTO, headers, HttpStatus.OK);
else return new ResponseEntity<PaisDTO>(headers, HttpStatus.OK);
}
Solution 1:
You have to implement you entity class with Serializable
Solution 2:
Your class should have getter and setter
In my case the getter and setter were given protected access modifiers. so I changed them to public and vola it worked
First, if you're using #RestController annotation you don't need the #ResponseBody annotation, get rid of that.
Second if you're trying to have REST Controller, then you're missing a few things, do it like this:
#RequestMapping(value = "/sigla/{sigla}", method = RequestMethod.GET, consumes = "application/json", produces="application/json")
public ResponseEntity<PaisDTO> obterPorSigla(#PathVariable String sigla) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
PaisDTO paisDTO = service.obterPorSigla(sigla);
if(paisDTO != null) return new ResponseEntity<>(paisDTO, headers, HttpStatus.OK);
else return new ResponseEntity<>(headers, HttpStatus.OK);
}
In the example above if you'll get null then you'll return an empty response JSON.
The only way that I could find was to create an empty class
#JsonSerialize
public class EmptyJsonBody {
}
Then add this to your response
#PostMapping(value = "/sigla/{sigla}")
public ResponseEntity obterPorSigla(#PathVariable String sigla) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
PaisDTO paisDTO = service.obterPorSigla(sigla);
ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.ok().headers(headers);
if(paisDTO != null) {
return responseBuilder.body(paisDTO);
} else {
return responseBuilder.body(new EmptyJsonBody());
}
}
One Way is to convert the List< Map < String, Object>> into List(object); Given Below
List<Map<String, Object>> ls = jdbcTemplate.queryForList(query);
List<Users> ls_o = new ArrayList<>(ls_o);
for (Map<String, Object> row : ls) {
ls_o.add(row);
}
return new ResponseEntity<List<User>>(ls_o, HttpStatus.OK);
Is there any effiecient way to directly convert the jdbcTemplate result into json object?
If you are using Maven as you build script. Add following dependency
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.5</version>
</dependency>
Modify Code as shown below
private final ObjectMapper mapper = new ObjectMapper();
public ResponseEntity myMethod(){
List<Map<String, Object>> ls = jdbcTemplate.queryForList(query);
final String str = mapper.writeValueAsString(ls);
return new ResponseEntity<List<User>>(str, HttpStatus.OK);
}
However if you are using Spring 4+ MVC, I would recommend you to use #RestController
Which does most of the job for you here is an example for you, here is simple example
#RestController
class MyTestClass{
#RequestMapping("/myMethod")
public List<Map<String, Object>> myMethod(){
return jdbcTemplate.queryForList(query);
}
}
Note: In Both Above cases you need to convert The Object class to a Exact class to work.
Is there a better way (possibly using annotations) to add a mixin to a spring controller.
Currently I am doing this:
#RequestMapping(value = "/accounts",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET,
params = "q")
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public final String getAccountsViaQuery(#RequestParam("q") final String query)
throws JsonGenerationException, JsonMappingException, IOException {
final List<Account> matchingAccounts = accountService.findByAccountNameOrNumber(query);
ObjectMapper mapper = new ObjectMapper();
SerializationConfig serializationConfig = mapper.getSerializationConfig();
serializationConfig.addMixInAnnotations(Account.class, Account.SearchJsonMixin.class);
return mapper.writeValueAsString(matchingAccounts);
}
I would rather do this
#RequestMapping(value = "/accounts",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET,
params = "q")
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public final List<Account> getAccountsViaQuery(#RequestParam("q") final String query)
throws JsonGenerationException, JsonMappingException, IOException {
return accountService.findByAccountNameOrNumber(query);
}
Looks much better to me, no boilerplate code and the return type is compiler checked.
Is is possible to use some sort of annotation on my controller to add a json mixin?
Wrote an annotation to solve this issue.
https://github.com/jackmatt2/JsonResponse
I am beginning with REST techniologies, and I choose Spring 3.2 and Jackson 2.2 . I have small question. I created REST API and it looks like this:
#Controller
public class WorkersController {
#Autowired
public DatabaseService dbService;
#ResponseBody
#RequestMapping(value="/workers", method = RequestMethod.GET, produces = "application/json")
public ArrayList<Worker> getAllWorkersFromDatabase() {
}
#ResponseBody
#RequestMapping(value="/workers/new", method = RequestMethod.POST, produces = "application/json", consumes="application/json")
public String saveWorker(#RequestBody final WorkerDTO workerDto) {
}
#ResponseBody
#RequestMapping(value="/workers/{workerid}", method = RequestMethod.GET, produces = "application/json")
public Worker getWOrkerByDatabaseId(#PathVariable Integer workerid) {
}
#ResponseBody
#RequestMapping(value="/workers/{workerid}/edit", method = RequestMethod.PUT, produces = "application/json")
public String editWorker(#PathVariable Integer workerid, #RequestBody Worker worker) {
}
}
When I make HTTP GET all is ok but I have problem with POST. When I am calling saveWorker() method I get:
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method
I imported required libraries:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
I think the main problem is in configuration files and #RequestBody cant map JSON to DTO. It is my Configuration:
#Configuration
#ComponentScan(basePackages = "org.schedule.service")
#EnableWebMvc
#Import(DatabaseSpringConfig.class)
public class ServiceSpringConfig extends WebMvcConfigurationSupport{
#Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> jsonTypes = new ArrayList<>(jsonConverter.getSupportedMediaTypes());
jsonTypes.add(MediaType.TEXT_PLAIN);
jsonTypes.add(MediaType.APPLICATION_JSON);
jsonConverter.setSupportedMediaTypes(jsonTypes);
converters.add(jsonConverter);
}
}
My DTO:
public class WorkerDTO implements Serializable {
private static final long serialVersionUID = 1L;
public String name;
public String surname;
public WorkerDTO() {
}
}
Json:
{
"name": "asdssss",
"surname": "asdssssss"
}
And http call:
localhost:8080/Schedule-service/workers/new?Content-type=application/json
Thanks for all replies.
The request
localhost:8080/Schedule-service/workers/new?Content-type=application/json
has a request parameter with name Content-Type and value application/json.
HttpMessageConverter classes, and MappingJackson2HttpMessageConverter in particular, don't look for request parameters, they look for headers.
You need to specify a Content-Type header for your request.
I was creating file upload using ExtJS 4 frontend and Spring 3 as backend. File upload works, but the response from server has wrong content type. When I send {success:true} using Map<String, Object> serialized by Jackson, ExtJS returns error
Uncaught Ext.Error: You're trying to decode an invalid JSON String: <pre style="word-wrap: break-word; white-space: pre-wrap;">{"success":true}</pre>
Why is my response wrapped with <pre> tag? I've searched and found out that I should change response type to text/html for example. But changing content type in servlet response didn't help
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody Map<String, Object> upload(
FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
response.setContentType("text/html");
// File processing
Map<String, Object> jsonResult = new HashMap<String, Object>();
jsonResult.put("success", Boolean.TRUE);
return jsonResult;
}
When I change return value of upload method to String, everything works correctly, but I want to return Map and have it serialized by Jackson
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody String upload(
FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
// File processing
return "{success:true}";
}
My Spring configuration
<bean
id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
</bean>
<bean
id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
<ref bean="stringHttpMessageConverter" />
</list>
</property>
</bean>
How to tell Spring to return correct content type? Why is response of this method incorrect when response of other methods is interpreted correctly?
You need to set the content-type of response as "text/html".
If the content-type is "application/json" will have this problem. It's odd.
You can return boolean if you need only to return value of success :
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody boolean upload(
FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
return true; //or false
}
Well, not really the best solution, but it solves the problem. I've created class, which has Map inside and method for adding parameters into Map. Also there is implemented method toString().
public class ExtJSJsonResponse {
/** Parameters to serialize to JSON */
private Map<String, Object> params = new HashMap<String, Object>();
/**
* Add arbitrary parameter for JSON serialization.
* Parameter will be serialized as {"key":"value"};
* #param key name of parameter
* #param value content of parameter
*/
#JsonIgnore
public void addParam(String key, Object value) {
params.put(key, value);
}
/**
* Gets all parameters. Also is annotated with <code>#JsonValue</code>.
* #return all params with keys as map
*/
#JsonValue
public Map<String, Object> getParams() {
return params;
}
/**
* Returns specified parameter by <code>key</code> as string "key":"value"
* #param key parameter key
* #return "key":"value" string or empty string when there is no parameter
* with specified key
*/
private String paramToString(String key) {
return params.containsKey(key)
? "\"" + key + "\":\"" + params.get(key) + "\""
: "";
}
/**
* Manually transforms map parameters to JSON string. Used when ExtJS fails
* to decode Jackson response. i.e. when uploading file.
* #return
*/
#Override
#JsonIgnore
public String toString() {
StringBuilder sb = new StringBuilder("{");
String delimiter = "";
for (String key : params.keySet()) {
sb.append(delimiter);
sb.append(paramToString(key));
delimiter = ",";
}
sb.append("}");
return sb.toString();
}
}
So when Uncaught Ext.Error: You're trying to decode an invalid JSON String occurs, you simply do this
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody String upload(
FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
ExtJSJsonResponse response = new ExtJSJsonResponse();
// File processing
response.addParam("success", true);
response.addParam("message", "All OK");
return response.toString();
}
In other methods which doesn't have problem with serialization you can simply call return response; and it will be automatically serialized.
Method toString() will work only for simple classes such as String. For more complicated classes you'll have to change it.
I think you can use the "produces" attribute of Spring's #RequestMapping annotation:
#RequestMapping(value = "/upload", method = RequestMethod.POST, produces = MediaType.TEXT_HTML_VALUE)
public #ResponseBody Map<String, Object> upload(
FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
// File processing
Map<String, Object> jsonResult = new HashMap<String, Object>();
jsonResult.put("success", Boolean.TRUE);
return jsonResult;
}
In config file, you should make this Content-Type available:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<array>
<value>text/html</value>
<value>application/json</value>
</array>
</property>
</bean>
This is available in Spring 3.1.1.RELEASE, maybe in older versions it doesn't work.