Retrieving all POST data parameters into map with Java Jersey - java

I'm trying to gather all parameters of an HTTP POST request into a map, however it's not working.
With a GET, I used:
#Context
private HttpServletRequest request;
and
#GET
#Path("/{uuid}/invoke/{method}")
public Response invokeMethod (
#PathParam("uuid") String uuid,
#PathParam("method") String methodz
) {
Map<String, String[]> params = request.getParameterMap();
and it returned the map. However, when sending form data via a POST instead of inline with the URL, the map is being returned as NULL.
Is there a similar way to retrieve all the parameters at once using a POST?
EDIT:
My data is being submitted as a serialized JSON, so using a cURL statement as an example:
curl --data "firstname=john&lastname=smith" http://localhost:8080/uuid1/apitest/method1
Ideally, I'd want to get a hashmap of something like:
ParamMap["firstname"] = "john"
ParamMap["lastname"] = "smith"
Also, the parameters won't be static, so this cURL:
curl --data "job=construction" http://localhost:8080/uuid2/apitest/method2
would result in:
ParamMap["job"] = "construction"

Finally got this resolved using this thread:
Jersey: Consume all POST data into one object
My new function is:
#POST
#Path("/{uuid}/invoke/{method}")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response invokeMethod (
MultivaluedMap<String,String> params,
#PathParam("uuid") String uuid,
#PathParam("method") String method
) {
Variable 'params' is now a map containing form data key/value pairs.

You can try following code
#POST
#Path("/{uuid}/invoke/{method}")
public Response invokeMethod (
#Context UriInfo request
) {
Map<String, List<String>> params = request.getPathParameters();
}
You no need to write
#Context
private HttpServletRequest request;
Now You can get idea...

Related

Spring #RestController how to get header at class level [duplicate]

I am new to web programming in general, especially in Java, so I just learned what a header and body is.
I'm writing RESTful services using Spring MVC. I am able to create simple services with the #RequestMapping in my controllers. I need help understanding how to get HTTP header information from a request that comes to my method in my REST service controller. I would like to parse out the header and get some attributes from it.
Could you explain how I go about getting that information?
When you annotate a parameter with #RequestHeader, the parameter retrieves the header information. So you can just do something like this:
#RequestHeader("Accept")
to get the Accept header.
So from the documentation:
#RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
#RequestHeader("Keep-Alive") long keepAlive) {
}
The Accept-Encoding and Keep-Alive header values are provided in the encoding and keepAlive parameters respectively.
And no worries. We are all noobs with something.
You can use the #RequestHeader annotation with HttpHeaders method parameter to gain access to all request headers:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers) {
// Use headers to get the information about all the request headers
long contentLength = headers.getContentLength();
// ...
StreamSource source = new StreamSource(new StringReader(body));
YourObject obj = (YourObject) jaxb2Mashaller.unmarshal(source);
// ...
}
My solution in Header parameters with example is user="test" is:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers){
System.out.println(headers.get("user"));
}
You can use HttpEntity to read both Body and Headers.
#RequestMapping(value = "/restURL")
public String serveRest(HttpEntity<String> httpEntity){
MultiValueMap<String, String> headers =
httpEntity.getHeaders();
Iterator<Map.Entry<String, List<String>>> s =
headers.entrySet().iterator();
while(s.hasNext()) {
Map.Entry<String, List<String>> obj = s.next();
String key = obj.getKey();
List<String> value = obj.getValue();
}
String body = httpEntity.getBody();
}

How to receive application/x-www-form-urlencoded Request parameters in Spring rest controller

I'm trying to write a rest endpoint which receives application/x-www-form-urlencoded. But the endpoint does not accept request parameters for #RequestBody or #RequestParam
I Have tried using MultiValueMap to grab the request parameters. But I always get 0 parameters.
Is there a way to get request values to the MultiValueMap or some other POJO class.
AD=&value=sometestvalue - This is the application/x-www-form-urlencoded requestbody. I'm trying to do the request using postman
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap formData,
HttpServletRequest servletRequest, ServiceContext serviceContext){
log.info("!--REQUEST START--!"+formData.toString());
}
You need to use MultiValueMap<String, String>
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap<String, String> formData) {
System.out.println("!--REQUEST START--!" + formData.toString());
return null;
}
You do not use #RequestParam on a POST request as the data is not in the URL as in a GET request.
You should use #RequestBody (doc) along with registering appropriate HttpMessageConverter. Most likely you should use: FormHttpMessageConverter
Try #ResponseBody. Then, change to a String, not a MultiValueMap, to see if the body comes in to the request.

Converting a POJO to Form Data in Java

I have a POJO of the form:
#Data
public class BaseRequest {
private String type;
private Map<String, Object> details;
private Map<String, Object> signature;
}
I have a service running which only accepts Content Type: "application/x-www-form-urlencoded".
I have written a client in Java which uses Spring's RestTemplate to make calls.
public String getInvoice(BaseRequest req, String url) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req, headers);
String response = this.restTemplate.postForObject(url, httpEntity, String.class);
return response;
}
However, it throws an error:
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.x.y.z.BaseRequest] and content type [application/x-www-form-urlencoded]
It works if I set the content type as JSON:
headers.setContentType(MediaType.APPLICATION_JSON);
I know it works for JSON because I have configured my RestTemplate Bean with JacksonHTTPMessageConverter. So I can easily convert POJOs to application/json. However, I am not able to figure out how to do that with application/x-www-form-urlencoded.
I've been searching this for awhile now, and the only solution which I've found is to write my own converter to convert my BaseRequest class to Spring's MultiValueMap, and then Spring's FormHttpMessageConverter will automatically handle it. But I want to avoid doing that. Is there any other way around this?
Any leads would be appreciated. Thanks!
EDIT:
My question is different from #JsonProperty not working for Content-Type : application/x-www-form-urlencoded. The conversion happening there is about accepting data in application/x-www-form-urlencoded and converting it to a POJO. My question is about converting a POJO to application/x-www-form-urlencoded while using Spring's resttemplate to make calls. And like I mentioned, I know I can achieve this by writing my own converter to convert my POJO to Spring's MultiValueMap. However, I want to know if I can avoid doing this.
EDIT:
Dump of $_POST on the API when I send my data as MultiValueMap<String, Object>:
"array(0) {
}"
Dump of $_POST on the API when I send my data through Postman in the correct format:
"array(2) {
["type"]=>
string(16) "abcd"
["details"]=>
array(1) {
["template_file"]=>
string(16) "x.html"
}
}"
Try to convert your nested object in request payload to the org.springframework.util.MultiValueMap. Add and implement converter method in your POJO
public class BaseRequest {
// ...
public MultiValueMap<String, Object> toMap() {
MultiValueMap<String, Object> result = new LinkedMultiValueMap<>();
result.add("type", type);
result.put("details", details);
result.put("signature", signature);
return result;
}
}
Now use it during request creation
HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req.toMap(), headers);
That is caused because inside FormHttpMessageConverter which performs actual conversion method canRead(Class<?>, MediaType) checks if MultiValueMap.class.isAssignableFrom(clazz) where clazz is your payload object. In your case it failed, so FormHttpMessageConverter skipped.
Hope it helps!

Java check GET request info

I'm working with Facebook messenger app (chatbot) and I want to see what GET request I'm receiving from it. I'm using Spring Framework to start http server and ngrok to make it visible for facebook.
Facebook sending webhooks to me and i receive them, but i don't understand how to extract data from this request. Here what i get when I try HttpRequest to receive GET request. ngrok screenshot (error 500).
When I tried without HttpRequest, i had response 200 (ok).
What do i need to put to parameters of my find method to see GET request data?
My code:
#RestController
public class botAnswer {
#RequestMapping(method= RequestMethod.GET)
public String find(HttpRequest request) {
System.out.println(request.getURI());
String aaa = "222";
return aaa;
}
}
I guess HttpRequest will not help you here. For simplicity, just change HttpRequest to HttpServletRequest. You can access all query string parameters from it using request.getParameter("..."). Something like the following should work:
#RequestMapping(value = "/", method = RequestMethod.GET)
public String handleMyGetRequest(HttpServletRequest request) {
// Reading the value of one specific parameter ...
String value = request.getParameter("myParam");
// or all parameters
Map<String, String[]> params = request.getParameterMap();
...
}
This blog post shows how to use the #RequestParam annotation as an alternative to reading the parameters from HttpServletRequest directly.

Java Spring MVC - Send JSON request body error

I am trying to send a JSON string as a request to my application. This is my code:
#RequestMapping(
value = "/mylink/upload",
method = RequestMethod.POST,
consumes ="application/json",
produces = "application/json")
public
#ResponseBody
List<Upload> upload(
#RequestParam(value = "hdfsLocation") String hdfsLocation
) throws Exception {
return S3HdfsTransfer.uploadFromHDFS(hdfsLocation);
}
I am trying to send a request with Postman. The method I use is POST, the header contains: Accept "application/json",Content-Type "application/json", the request body is the following:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
This is the response I get. If I put the parameter in the URL, it works.
{
"httpStatus": 500,
"appErrorId": 0,
"message": "Required String parameter 'hdfsLocation' is not present",
"trackingId": "8c6d45fd-2da5-47ea-a213-3d4ea5764681"
}
Any idea what I am doing wrong?
Thanks,
Serban
Looks like you have confused #RequestBody with #RequestParam. Do either of following :
Pass the request param as a request param(not as a body). Like, (encoded)
http://example.com?hdfsLocation=http%3A%2F%2Fexample.com%3FhdfsLocation%3Dhdfs%3A%2F%2F145.160.10.10%3A8020
Replace the #RequestParam with #RequestBody. If you are sending a body, don't send it along with request param. Those are two different things.
I guess you over looked :)
Shouldn't it be #RequestBody instead of #RequestParam?
Also, even after using #RequestBody, the whole of the JSON string:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
will be the value of String hdfsLocation and not just the hdfs url. Hence, you'll have to JSON parse that JSON by yourself to get just the hdfs url.

Categories

Resources