Retrieve POST parameters only (Java) - java

Does anyone know of a way to get only POST parameters from an HttpServletRequest object?
IE, PHP has the $_POST superglobal and Perl's CGI.pm will only retrieve POST parameters if the HTTP method is POST (by default).
HttpServletRequest.getParameter(String) will include the GET URL parameters even if the HTTP method is POST.

From my understanding, there are no such things as POST parameters and GET parameters in HTTP, there are POST and GET methods. When a request is made using the POST method, parameters go within the message body. In case of a GET request, parameters go in the URL.
My first thought was that it was an implementation bug in your servlet container. But, since things are not always as you expect, java servlet specification (at least the 2.4 version) does not differentiate between the two kind of parameters. So, there is no way to obtain post or url parameters using the servlet API.
Surely you already have a plan B. But, just in case, I post two alternatives that came to my mind:
If you have access to the parameter name definition, you could use a prefix to differentiate between the two when you iterate the getParameterNames() result.
You could parse the URL creating an URL object and using getQuery() method to obtain just the parameters. Then, parse the parameters on the query string using some utility class such as ParameterParser in HttpClient library. And finally, subtract that names from the getParameterNames() result.

I guess one way might be to manually parse HttpServletRequest.getQueryString() and check that a parameter is not present in it.
A naive implementation (ignoring url-escaped key values) would go something like this (untested) :
public boolean isInQuery(HttpServletRequest request, String key) {
String query = request.getQueryString();
String[] nameValuePairs = query.split("&");
for(String nameValuePair: nameValuePairs) {
if(nameValuePair.startsWith(key + "=")) {
return true;
}
}
return false;
}

Couldn't you just get the parameters from the HttpServletRequest within doPost or doGet in a subclass of HttpServlet?
Anything you grab (via getParemeter) inside of doPost is a POST and anything inside of doGet is a GET.

I think you could do something with getMethod() available from the HttpServletRequest Interface.
Java doc 1.6
This is also available in 1.4 and 1.5.

I'm not sure if this would work, but you could try extracting the raw content of the POST body using request.getReader(). The container may remove that data before handing control to your application, though, and even if it didn't, you'd have to decode the parameter string yourself.

The question was answered in this related post:
Normaly you can GET and POST parameters in a servlet the same way:
request.getParameter("cmd");
But only if the POST data is encoded as key-value pairs of content
type: "application/x-www-form-urlencoded" like when you use a standard
HTML form.

Related

Passing array with in GAE Endpoints

I am just trying out the first example of GAE Endpoints, I modified the sample API Method to resemble this.
#ApiMethod(name = "sayHi")
public MyBean sayHi(#Named("name") String[] names) {
My expectation is to receive a array of strings.
Now when I use the Google API Explorer to test this, [https://apis-explorer.appspot.com/apis-explorer/]
it generates API like this
POST https://myprojectid.appspot.com/_ah/api/myApi/v1/sayHi/arg1/arg2/arg3?fields=data
It eventually returns 404 error. Since the endpoint is not recognized.
What am I doing wrong here? In fact explorer shows name as String not String[]. Any help is appreciated!
First things first: does this work when there is a single String parameter? There's some servlet mapping magic that needs to happen to expose endpoints, and if that is not present in the project, things won't work. See this link to make sure your web.xml is as it should be.
Looking at this link, it seems that if your method parameter is a basic type (not a real Java object), and if it is not specifically included in a #Path annotation, there's some uncertainty in what will happen in your Api:
Path parameters are the method parameters included in the path property of the #ApiMethod annotation. If path is unspecified, any parameters not annotated with #Nullable or #DefaultValue will be automatically added to the path (they will be path parameters).
So it seems that by not including "name" in a #Path annotation, the docs don't state what the format of the path will be. The generated descriptor that the Explorer is looking at seems to think the right answer is /names[0]/names[1]/names[2], kind of like C-style varargs. It might be this disconnect that causes your 404 to happen. Can you try by including "name" in a #Path annotation?
Instead of having an array as a parameter of the endpoint method, you should put an object (java bean) which contains an array as a property.
Then you get the object in your method and you just read the property and treat it as an array.
Edit after some more research, following your comment
Indeed when you try to pass an array as a Path parameter it doesn't work. The different elements of your array are added to the URL (as you show in your question) and it generates a 404 Not Found error. The trick is that you should pass this array as a Query parameter and not a Path Parameter. See this doc: https://cloud.google.com/appengine/docs/java/endpoints/parameter-and-return-types#path_parameters
And indeed, if you do something like that it works very well:
#ApiMethod(name = "sayHi",
path = "sayHiWithName")
public MyBean sayHi(#Named("name") String[] names) {
MyBean response = new MyBean();
response.setData("Hi, " + names[0] + names[1]);
return response;
}
Note that the parameter is NOT added to the path (i.e. we don't have a path like sayHiWithName/{name}).

Spring MVC : Using model.addAttribute() in Controller to send various Lists to Ajax method

I am working on a Spring-MVC application in which I want to send different types of java.util.List to the AJAX method. I don't know if we can use model.addAttribute in the controller when giving data to AJAX method.
Situation is :
#RequestMapping(value=/mappingurl)
public #ResponseBody void sendDataToAjax(){
List<Item1> item1;
List<Item2> item2;
List<Item3> item3;
model.addAttribute("item1collection",item1);
model.addAttribute("item2collection",item2);
model.addAttribute("item3collection",item3);
}
Will this work when it is an AJAX method, if not, what can I do so I can send List of objects and access it inside AJAX method. I hope my question is clear, if not, please let me know, I will improvise. Thanks. :-)
You won't have any problem adding several attributes to your model. When you return to client side you will be able to get them in an AJAX request.
Problem here is you can't use java.util.List objects by javascript at client-side, so you must create Json objects or convert to array the java.util.List.
The only thing i would change in your code is to add a response to catch succes or fail of the method:
public #ResponseBody String sendDataToAjax(){
// do your stuff and return "KO" if something goes wrong
return "OK"; // if success
}
This could be better done by implementing an enum class... but this is a faster way
After this, you can catch inside the ajax request the result of the server-side operatiion and continue in according to it.
IMHO answer is no , you can't iterate or print the Arraylist inside the AJAX response.
You can instead convert it into JSON-array and iterate it in the ajax response. A nice startup example,
Converting a Java ArrayList of strings to a JavaScript array

How can I configure Square's Retrofit Client to handle a request with a variable number of parameters

I'm building an Android App and am using Square's Retrofit library for short-lived network calls. I'm relatively new to Java and Android. Until now I've constructed requests like so:
#GET("/library.php")
void library(
#Query("one_thing") String oneThing,
#Query("another_thing") String anotherThing,
Callback<Map<String,Object>> callback
);
And called them like so:
service.library(oneThing, anotherThing, callback);
I need to implement a request that accepts a variable number of parameters, not more than 10 or so. It's cumbersome to have to define them individually and pass null or something for the ones that aren't present for a given request. Is there a way to define an interface for a request such that it accepts a variable number or parameters and auto-constructs #Querys for each element in the parameter dictionary/map? Something like this:
#GET("/library.php")
void library(
Map<String,Object> parameters,
Callback<Map<String,Object>> callback
);
service.library(parameters, callback);
Thanks in advance for any tips.
Edit: passing null for params that aren't pertinent to the request wont work in this case. Ideally I'd be able to set/create #Querys based on the parameter dictionary, so that keys wont become a #Query if their value is null.
Edit: I'm specifically looking for a solution that works with GET requests.
You could always try passing the parameters as a HTTP Body instead, such as in this example (note: I'm the author)
But as you suggest, use a Map with your values instead, so this might work for you:
#POST("/library.php")
public void library(#Body Map<String, Object> parameters, Callback<Map<String,Object>> callback);
It's a bit late but I'll post it anyway just in case someone found the same problem on Google.
They've introduced the Annotation #QueryMap
This annotation let you pass and object that implements Map class, is not as nice as Post requests that let's you pass an Object as parameter but it get the works done.
#GET("/library.php")
public void library(#QueryMap Map<String, Object> parameters, Callback<Map<String,Object>> callback);

Can we have more than one #Path annotation for same REST method [duplicate]

This question already has answers here:
JAX-RS: Multiple paths
(4 answers)
Closed 2 years ago.
Can we have more than one #Path annotation for same REST method i.e. the method executed is the same, but it is executed on accessing more than one URL?
E.g.: I want to run the searchNames() method on both http://a/b/c and http://a/b.
You can't have mutliple #Path annotations on a single method. It causes a "duplicate annotation" syntax error.
However, there's a number of ways you can effectively map two paths to a method.
Regular expressions in #Path annotation
The #Path annotation in JAX-RS accepts parameters, whose values can be restricted using regular expressions.
This annotation:
#Path("a/{parameter: path1|path2}")
would enable the method to be reached by requests for both /a/path1 and /a/path2. If you need to work with subpaths, escape slashes: {a:path1\\/subPath1|path2\\/subPath2}
Serving responses with a redirection status code
Alternatively, you could set up a redirection. Here's a way to do it in Jersey (the reference implementation of JAX-RS), by defining another subresource. This is just an example, if you prefer a different way of handling redirections, feel free to use it.
#Path("basepath")
public class YourBaseResource {
//this gets injected after the class is instantiated by Jersey
#Context
UriInfo uriInfo;
#Path("a/b")
#GET
public Responce method1(){
return Response.ok("blah blah").build();
}
#Path("a/b/c")
#GET
public Response method2(){
UriBuilder addressBuilder = uriInfo.getBaseUriBuilder();
addressBuilder.path("a/b");
return Response.seeOther(addressBuilder.build()).build();
}
}
Using a servlet filter to rewrite URLs
If you're going to need such functionality often, I suggest intercepting the incoming requests using a servlet filter and rewriting the paths on the fly. This should help you keep all redirections in one place. Ideally, you could use a ready library. UrlRewriteFilter can do the trick, as long as you're fine with a BSD license (check out their google code site for details)
Another option is to handle this with a proxy set up in front of your Java app. You can set up an Apache server to offer basic caching and rewrite rules without complicating your Java code.
As explained in Tom's answer, you can not use more than one #Path annotation on a single method, because you will run into error: duplicate annotation at compile time.
I think the simplest way to get around this is to use method overloading:
#Path("{foo}")
public Response rest(#PathParam("foo") final String foo) {
return this.rest(foo, "");
}
#Path("{foo}/{bar}")
public Response rest(#PathParam("foo") final String foo,
#PathParam("bar") final String bar) {
return Response.ok(foo + " " + bar).build();
}
You could also use more different method names if you run into the case where multiple overloaded methods have the signature.
Another solution for your particular example:
http://a/b/c
http://a/b
Let's suppose that:
/a is for the resource class
/b/c and /b are the paths for the methods
because a full path looks like:
<protocol><host><port><app><url-pattern><resource-path><method-path>.
Use optional parameter
#Path("/b{c : (/c)?}")
public Response searchNames(#PathParam("c") String val) {
...
}
The example above works for all examples like:
/b
/b/
/b/c
/b/c/
but when c is provided, the val is /c (it has a / before).
If you want to fix the problem above (to avoid Java parsing), you need something more complex:
#Path("/b{slash : (/)?}{c:((?<=/).*)?}")
which will return only c (not /c) for the 3rd bullet point, but for the 4th bullet point it will return c/ which has to be parsed in Java.
But for your case ("the method executed is the same"), don't worry about parsing because you don't have different actions.
If you are using Spring then try
#RequestMapping(value = {"/def", "/abc"}, method = RequestMethod.POST)
This will work for both /abc and /def.
– sSaroj Nov 17 '17 at 10:13

Is it possible to get a #PathParam or #QueryParam from the MessageBodyReaderContext in a RestEASY MessageBodyReaderInterceptor?

My service:
#POST
public String setData(#QueryParam("id") Long is, MyObject payload) {
...
}
or
#POST
public String setData(#PathParam("id") Long is, MyObject payload) {
...
}
My interceptor on the server:
Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException {
Class mypayloadtype = context.getType;
InputStream mypayloadinpustream = context.getInputStream();
Long myidparam = ???????? // how to get the query or path param here?
}
EDIT: To be a bit more concrete:
What I'd like to do is to grab the XML and store it based on the parameters in a separate audit system. Maybe PreProcessInterceptor / PostProcessInterceptor are the better choices?
Any hints or alternative ways to get the param when the xml is still available for preprocessing?
Miguel
I just stumbled over the same problem today. I needed the #PathParams and #QueryParams in the read() method and ended up with something like this:
public class MyInterceptor implements PreProcessInterceptor, MessageBodyReaderInterceptor
{
private static ThreadLocal<UriInfo> uri = new ThreadLocal<UriInfo>();
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
{
uri.set(request.getUri);
...
}
public Object read(MessageBodyReaderContext context)
{
String param = uri.get().getPathParameters().getFirst("myidparam");
...
}
}
Although when thinking about it now - I'm not quite sure, if just using PreProcessInterceptor/PostProcessInterceptor will also do the trick for my (and maybe your) problem. I'll have another look tomorrow.
I am not an expert on the topic but to me it seems as if the MessageBodyReaderContext interface does not really know if it is on the server or the client side, so it cannot expose the request or its parameters / path parts etc.
So as far as I know this is not possible.
If your code knows that it lives on the server side of the rest
communication, maybe you can use a servlet filter to store the request
in a ThreadLocal and then access it from there while the request is
handled, somewhat similar to RequestContextFilter / RequestContextHolder from the spring framework? (Then the request object does not know anything about the annotations of your service, but instead one has to extract the information manually from the request. This means to have the same information in two places, so there has to be a better solution ...)
Edit: after looking at some examples I get the vague feeling that if you want to read the input stream to create an object and add path parameters to it, MessageBodyReaderInterceptor is simply not the way to go. Instead set up a MessageBodyReader which constructs the object from the request body data, and this then will be passed into the public String setData(#PathParam("id") Long is, MyObject payload), assuming that this method is annotated with a #Consumes which matches the #ConsumeMime annotation for the MessageBodyReader. There you might be able in the setData to set the missing id on the object read from the request body. Some examples related to this seem to be here: How to get full REST request body using Jersey? (but for Jersey, not jBoss :-/)
However I am not sure if that works for you, and I also feel I completely overestimated my ability to answer this question appropriately, so I hope someone more knowledgeable comes in with a better solution.

Categories

Resources