How to get JSON as Response in Spring MVC? - java

I am trying to return response as JSON. After searching I found solution to add headers = "Accept=application/json" in RequestMapping. But still it is not working .
It is throwing error HTTP Status 406 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Here is my controller code :
#RestController
public class EmployeeController {
private EmployeeService employeeService;
#Autowired(required = true)
#Qualifier(value = "employeeService")
public void setEmployeeService(EmployeeService employeeService){
this.employeeService = employeeService;
}
#RequestMapping(value = "/test",method = RequestMethod.GET)
public String test(){
return "{\"name\":\"xyz\"}";
}
#RequestMapping(value = "/employees",method = RequestMethod.GET,headers = "Accept=application/json")
public List<Employee> listEmployees(){
List<Employee> employees = this.employeeService.getEmployees();
return employees;
}
}
Where am I doing wrong?

The simple way to generate JSON, XML response is #ResponseBody annotation.
#RequestMapping(value =" /jsonPostSingle", method = RequestMethod.GET)
#ResponseBody
public PostModel generateJSONPostsingle(#ModelAttribute("postModel") PostModel postModel) {
if(postModel.getPostId() == 1) {
postModel.setTitle("post title for id 1");
} else {
postModel.setTitle("default post title");
}
return postModel;
}
This way you will be able to map your request to model class using #ModelAttribute.
Follow the complete tutorial Spring MVC : JSON response using #ResponseBody

I understand that you're trying to send a response from GET request of /employees.
if you are using Spring 3.1, try to use
#RequestMapping(value = "/employees",method = RequestMethod.GET, produces = "application/json")
instead of adding headers = "Accept=application/json"
More info:
if you want to specify type of data that will send with a request, you can use consumes attribute
example:
#RequestMapping(value="/foo", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
this will consumes and response with JSON type only
check this link about spring update http://spring.io/blog/2011/06/13/spring-3-1-m2-spring-mvc-enhancements/
Hope it helps

Related

Return XML or JSON from a REST controller based on request parameters

This is my controller:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
#ResponseBody
public Result generateResult(#Valid #RequestBody Request request) throws JsonProcessingException {
Result result = new Result();
// some code here
return result;
}
and this is my Request class:
#Data
#NoArgsConstructor
public class Request {
#NotNull
private String name;
private String type = "application/json";
}
the controller produces the correct output based on the Accept header in the request sent by the client. However, I want to send no Accept header and only send the following request:
{
"name": "my name",
"type": "application/xml"
}
Then based on the type the correct format should be output. I tried to add HttpServletResponse response to the parameter list of the controller method and then set the content type like this:
response.setHeader(CONTENT_TYPE, request.geType());
but it always returns json. any idea what else I should do?
I think a standard Spring's ResponseEntity builder give you all needed variety:
return ResponseEntity
.ok(//any object for json structure)
.headers(//any header)
.build();
Instead .ok() you can you any other method (that's http status code)
or
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.OK);
based on the comments I post this answer which worked for me. I changed my controller method like this:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE,
APPLICATION_XML_VALUE})
#ResponseBody
public ResponseEntity<Result> generateResult(#Valid #RequestBody Request request)
throws JsonProcessingException {
Result result = new Result();
// some code here
return ResponseEntity.accepted()
.headers(headers)
.body(result);
}

How should 'missing' request headers be handled by a Spring Boot Controller?

I am writing a Spring Boot application. My controller has 2 custom request headers. I was executing a couple of tests only to find out that my application returns a '404' when the headers are not present.
I however was expecting this to lead to a '400' error?
Can anyone elaborate why this is happening? And how I should handle it properly? As in tell the consumer of the service the headers are missing?
#RestController("fundsConfirmationController")
#RequestMapping(
value="/accounts/{accountId}/funds-confirmations",
headers = {"X-CAF-MSGID", "X-AccessToken"}
)
public class FundsConfirmationController implements FundsConfirmationControllerI{
private FundsConfirmationServiceI fundsConfirmationService;
#Autowired
public FundsConfirmationController(FundsConfirmationServiceI fundsConfirmationService){
this.fundsConfirmationService = fundsConfirmationService;
}
#GetMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> fundsConfirmation(#RequestHeader(value="X-CAF-MSGID") String messageId,
#RequestHeader(value="X-AccessToken") String accessToken,
FundsConfirmationRequest requestParams) { ... }
2 solutions to do the same.
First using #RequestHeader with required false
#RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
public void post(#RequestHeader(value="X-CAF-MSGID", required=false) String X-CAF-MSGID) {
if(X-CAF-MSGID == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}
Second using HttpServletRequest instead of #RequestHeader
#RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
public void post(HttpServletRequest request) {
String X-CAF-MSGID = request.getHeader("X-CAF-MSGID");
if(X-CAF-MSGID == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}

Swagger not picking methods with empty value

I am using swagger to document my rest apis.
An example:
#RequestMapping(value = "/abc/api/fruit", produces = "application/json")
#Controller
#Api(value = "Fruit", description = "api for fruits", produces = "application/json")
public class FruitResource {
#RequestMapping(method = RequestMethod.GET, value = "")
#ResponseBody
#ApiOperation(httpMethod = "GET", value = "Resource to get fruits", produces = "application/json", notes = "get fruits", response=Fruit.class)
public ResponseEntity<Fruit> getFruits() throws Exception {
return new ResponseEntity<Fruit>(someServiceCallToGetFruits(), HttpStatus.OK);
}
}
As seen above, the value in RequestMapping above the method is empty ("").
Because of this, this class and the method is not getting picked up by swagger.
But when I change the RequestMapping line above method to as below:
#RequestMapping(method = RequestMethod.GET, value = "/")
It starts working.
Is this a bug ? How can I make swagger to work with "" path values. I do not want to put "/" above all such methods.
There's no need to explicitly specify empty value if you don't want to add extend the API path for the particular method. Instead, the following annotation could be used:
#RequestMapping(method = RequestMethod.GET)
Or even
#GetMapping()

How to add cache-control to a #RestController servlet path?

I have a servlet to offer images resources via spring:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
return service.find(id);
}
Resulting http headers: Cache-control: "max-age=0".
Question: how can I control the cache header just for that method?
I guess you can implement the check of the last modified, Spring has support for that - ref API
Something like
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
youeObject = service.find(id);
ResponseBuilder builder = Response.ok(youeObject);
builder.cacheControl(CacheControl.maxAge(24, TimeUnit.HOURS)).cachePrivate());
return builder.build();
}
I ended as follows, which worked:
ResponseEntity.ok().lastModified(file.lastModified()).header("max-age", "86400");
I don't now why the approach with CacheControl class does not work.
I am using following:
public ResponseEntity getProducts(...) {
...
return ResponseEntity.ok().cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePrivate()).body(productProxy);
}
You can specify the cache's maxage by setMaxAge() of CacheControl class.
Also you can set it to public or private according to your requirement
**Follow the code snippets**
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/thumbnails", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getThumbnail(int id) {
BodyBuilder builder = (BodyBuilder) ResponseEntity.ok();
CacheControl cc = new CacheControl();
cc.setMaxAge(64, TimeUnit.HOURS);
cc.setPrivate(true);
builder.cacheControl(cc);
return builder.body(service.find(id));
}

How can I throw a 405 for all the HTTP methods that are not defined on my controller in spring boot?

I need to throw a 405 for all the http methods that are not defined in my controller. I am using spring boot is there a generic way to write it so that i do not have to add a method on my controller to read all the HTTP methods currently i do not get any response but it throws a 200 OK. Below is my controller that only has GET and PUT. I want to throw a 405 for all other methods.
#RestController("CardController")
#RequestMapping("/user/v1")
public class CardController {
#Autowired
ICardService iCardService;
#RequestMapping(value = "/{cardHolderId}/cards", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
#ResponseBody
public AllCardsVO getCards(#PathVariable("cardHolderId") final String id) {
return jsonObj;
}
#RequestMapping(value = "/{cardHolderId}/cards/{cardId}", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
#ResponseBody
public CardVO getCard(#PathVariable("cardHolderId") final String cardHolderId,
#PathVariable("cardId") final String cardId){
return jsonObj;
}
#RequestMapping(value = "/{cardHolderId}/cards/{cardId}", produces = "application/json; charset=utf-8", method = RequestMethod.PUT)
#ResponseBody
public CardVO putCard(#PathVariable("cardHolderId") final String cardHolderId,
#PathVariable("cardId") final String cardId, #RequestBody final RequestVO requestVO) {
return jsonObj;
}
This is what I wrote in the controller but it does not work for PATCH.
#RequestMapping(value = "/**", produces = "application/json; charset=utf-8", method = { RequestMethod.OPTIONS,
RequestMethod.DELETE, RequestMethod.PATCH, RequestMethod.POST })
#ResponseBody
public void options(HttpServletResponse response) {
throw new MethodNotAllowedException();
}
Is there a generic way i can do this in spring boot some sort of configuration override or service having this method in every api controller does not seem correct. IF this is the only way how do i get the PATCH working. I am getting a response for PATCH even though i do not have that defined.
ANy help is appreciated.

Categories