Spring Request mapping issue with only one header - spring

I have a request mapping that I want to be invoked ONLY when the request has Accept Header as application/json
#RequestMapping(path = "/payment", method = RequestMethod.GET, headers = "Accept=application/json" , produces = "application/json; charset=utf-8"
Above looks good but when the browser is refreshed this endpoint is called because when we look at the browser request headers, Accept header looks like this below which has */*
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
I only want to invoke this api only for application/json and not for everything else.
I tried adding another value to my header like headers = Accept=application/json,!text/html but that did not work.
Is there a workaround for this?
Thanks!

add consumes="application/json" in the #RequestMapping
#RequestMapping(path ="/payment", produces={"application/json"}, consumes="application/json" , method = RequestMethod.GET)

Related

How to support multipart/form-data and application/json by a same method spring boot Rest

I have a POST method that needs to support both multipart/form-data and application/json.
i.e. consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE }
When I'm supporting Multipart request, I need a multipart file and a multipart json which can be obtained by declaring as below:
Line 1-> #RequestPart("file") MultipartFile file, #RequestPart("jsonString") InputJsonVO inputJsonVO
Similarly when supporting an application/json, I need to accept the whole body as a Json content:
Line 2 -> #RequestBody InputJsonVO inputJsonVO
It works fine when we have either line 1 or line 2, but not both in the same method as parameters.
`#PostMapping(path = "/multipart", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE })
public String getMessage(#RequestPart(required=false, name="file") MultipartFile file, #RequestPart(required=false, name="jsonString") InputJsonVO inputJsonVO,
#RequestBody(required=false) InputJsonVO inputJsonVO2
)`
With this method declaration if I send a POST request:
POST /multipart HTTP/1.1
Host: localhost:8080
content-type: application/json
Content-Length: 335
<A Valid Json>
This works fine.
But when I sent a POST request as below from postman, it doesn't work:
POST /multipart HTTP/1.1
Host: localhost:8080
Content-Length: 650
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="/C:/Users/sdamarla/Downloads/J867FE94.jpeg"
Content-Type: image/jpeg
(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="jsonString"
Content-Type: application/json
<A valid Json>
----WebKitFormBoundary7MA4YWxkTrZu0gW
Gives below error:
Content type 'multipart/form-data;boundary=--------------------------335202067624768397899751' not supported]
Note: multipart request is working fine when removing the #RequestBody and the corresponding parameter.
Please let me know if this is a valid use case and if so where am I failing.
Just define two different methods, one for each representation:
#PostMapping(path = "/multipart", consumes = MediaType.APPLICATION_JSON_VALUE)
public String getMessage(#RequestBody InputJsonVO inputJsonVO) {
getMessage(null, inputJsonVO);
}
#PostMapping(path = "/multipart", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String getMessage(#RequestPart MultipartFile file, #RequestPart InputJsonVO inputJsonVO) {
// your code here
}

Http 400 using resttemplate postforobject

Below is the code which gives 400 bad request, tried various options with this but always ends up with 400 bad request, however the same works using OkHttp client
HttpHeaders hh = new HttpHeaders();
RestTemplate rt = new RestTemplate();
String reqBody = new ObjectMapper.writeValueAsString(“test msg”);
headers.set(“Accept”, “text/plain”);
headers.set(“content-type”,”application/json”);
headers.set(“authorization”, “Basic xxxxx”);
headers.set(“ibm-mq-rest-csrf-token”,”blank”);
HttpEntity<String> request = new HttpEntity<>(reqBody.toString());
ResponseEntity<Object> result = rt.postForObject(url, request, Object.class);
Below code works using okhttp
Your content does not appear to be JSON, in both cases it appears to be plain text. Therefore the header
Content-Type: text/plain
should be used rather than
Content-Type: application/json
I am unsure why this works in your OKHTTP example, unless perhaps the media type you use to build your post body somehow over-rides your Content-Type header?

How to remove charset=utf-8 in a Content-Type header, generated by spring-boot

I'm trying to send an mp4 file as a response body in spring-boot. I've tried setting the Content-Type header to video/mp4 using the following methods:
A RequestMapping annotation parameter:
#RequestMapping(value = "/movie.mp4", method = RequestMethod.GET, produces = "video/mp4")
Manually setting a header value via HttpHeaders, passed to return ResponseEntity.
Each time the resulting header is as follows:
Content-Type:video/mp4; charset=UTF-8
How do I get rid of the charset=UTF-8 postfix?
It took some debugging, but I found that HttpEncodingAutoConfiguration sets spring.http.encoding.force=true. If you set this to false in your application.properties, the charset will be omitted.

REST method's won't PUT or POST to the server

I'm trying to get some REST methods working in my Spring app but seem to be running into little success. I'm obviously missing something but I can't tell for the life of me what it would be. Here is my controller:
#Controller
public class IndexController {
static Logger log = Logger.getLogger(IndexController.class);
#Autowired
private ProvisionService provisionService;
#RequestMapping(value="/home/data", method=RequestMethod.GET,
headers="Accept=application/json")
public #ResponseBody List<Provision> getData() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = null;
if(principal instanceof UserDetails)
username = ((UserDetails)principal).getUsername();
return provisionService.getAllByUser(username);
}
//JSON put request - doesn't work currently
#RequestMapping(value="/home/data", method=RequestMethod.PUT,
headers="Content-Type=application/json")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateProvisions(#RequestBody List<Provision> provisions) {
log.info("Provisions: " + provisions.toString());
}
#RequestMapping(value={"/","/home"}, method=RequestMethod.GET)
public void showIndex() {}
}
Here is the main part of JSP that utilizes it:
<sf:form id="homeForm" method="put" action="${homeData_url}"></sf:form>
The form is submitted through Javascript when the user clicks on a button. Anyway, things work fine for the GET. I get Json returned with my List of objects, no problems. I then display that using Dojo and so far so good. However, when I try to return the Json with this form I'm getting a 405 - Request method 'POST' not supported error. As you can see I've got the method handler in my Controller so I'm really not sure what I'm doing wrong. I've taken those handler's out of the Spring in Action 3 book and it also resembles what some Spring docs and stuff say to do, but obviously I'm missing a key component. Anyone have any thoughts?
I do have the HiddenHttpMethodFilter mapped in my web.xml which is why I'm using the Spring form tag.
Anyway, any thoughts or help are appreciated. Thank you.
------------------UPDATE------------------
Here are the headers after I click on the button and get the 405 error, if it helps:
http://localhost:8080/NFI/home
POST /NFI/home HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
DNT: 1
Connection: keep-alive
Referer: http://localhost:8080/NFI/home
Cookie: JSESSIONID=584AC21ADE4F214904B9E7E2370363EF
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
Allow: GET, PUT
Content-Type: text/html;charset=utf-8
Content-Length: 1085
Date: Fri, 21 Oct 2011 15:39:26 GMT
Submitting a Form is done using POST. You get a "POST" not supported error.
Above, I see you are using a RequestMethod.PUT in your source code. There's no mention of POST at all.
Add you need to add a parameter _method with value PUT to your request. Not to the json content!
So in the first step I would change requested URL to /home/data?_method=PUT.
If this work you can search for an way how to add the _method parameter to the request content without disturbing the Json data.
You updated your question with the headers, could you also put the entire request out there (actual dumped values) to see the _method parameter(s) being sent?
Also, while I guess the headers=""-rules are valid they shouldn't be needed. You have a json converter bean that will do marshall and unmarshall based on content-type and accept headers, if no valid converter is found Spring will return an error.
The only reason to include it in the #RequestMapping would be if you had a method that actually did something else if you called it with xml instead of json and that sounds like a bad design.
Remove those header-rules and try again, make it as simple as possible and gradually add logic.

Problem with Spring 3 + JSON : HTTP status 406?

I'm trying to get a list of Cities by sending the State name through Ajax in my SpringMVC 3.0 project.
For the purpose, I've used the following call (using jQuery) in my JSP:
<script type="text/javascript">
function getCities() {
jq(function() {
jq.post("getCities.html",
{ stateSelect: jq("#stateSelect").val()},
function(data){
jq("#cities").replaceWith('<span id="cities">Testing</span>');
});
});
}
</script>
And here's my Controller code:
#RequestMapping(value = "/getCities", method = RequestMethod.POST)
public #ResponseBody List<StateNames> getCities(#RequestParam(value="stateSelect", required=true) String stateName,
Model model) {
// Delegate to service to do the actual adding
List<StateNames> listStates = myService.listCityNames(stateName);
// #ResponseBody will automatically convert the returned value into JSON format
// You must have Jackson in your classpath
return listStates;
}
But I get HTTP 406 error stating the following when i run it:
406 Not Acceptable
The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
I've used Jackson in my Maven dependencies & have defined in my context file.
I've googled extensively & I guess the problem is #ResponseBody is not automatically converting my List to appropriate JSON object.
My Firebug says:
Response Headers
Server Apache-Coyote/1.1
Content-Type text/html;charset=utf-8
Content-Length 1070
Date Sat, 12 Feb 2011 13:09:44 GMT
Request Headers
Host localhost:8080
User-Agent Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13
Accept */*
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Content-Type application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With XMLHttpRequest
Referer http://localhost:8080/MyApplication/
Content-Length 17
Cookie JSESSIONID=640868A479C40792F8AB3DE118AF12E0
Pragma no-cache
Cache-Control no-cache
Please guide me. What am i doing wrong?? HELP!!
As Peter had written in his comment, the cause of the problem is inability of Spring to load Jackson. It is not loaded by dependencies by default. After I've added the dependency
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.2</version>
</dependency>
the JSON was returned after typing the address in the browser, without any tricks with Accept headers (as it is supposed to do).
Tested on Tomcat 7.0.
You have incorrect response content type it supposed to be application/json.
You need to add jackson to your /lib directory.
and you should have
<mvc:annotation-driven />
In your serlvet-name.xml file.
In addition I recommend you to map your request as get and try to browse it with Google Chrome,to see if it returns correct result. It has very good json representation.
The problem is not on server side, but on the client one.
Take a look at the error message carefully: The requested resource (generated by server side) is only capable of generating content (JSON) not acceptable (by the client!) according to the Accept headers sent in the request.
Examine your request headers:
Accept */*
Try this way:
function getCities() {
jq(function() {
jq.post(
"getCities.html", // URL to post to
{ stateSelect: jq("#stateSelect").val() }, // Your data
function(data) { // Success callback
jq("#cities").replaceWith('<span id="cities">Testing</span>');
},
"json" // Data type you are expecting from server
);
});
}
This will change your Accept header to the following (as of jQuery 1.5):
Accept: application/json, text/javascript, */*; q=0.01
This will explicitly tell the server side that you are expecting JSON.
Using jQuery , you can set contentType to desired one (application/json; charset=UTF-8' here) and set same header at server side.
REMEMBER TO CLEAR CACHE WHILE TESTING.
I too had a similar problem while using the Apache HTTPClient to call few services. The problem is the client and not the server. I used a HTTPRequester with header accepting application/json and it worked fine.

Resources