Regarding REST Path Conflict - java

I am creating two methods(GET) in a REST service in which the URL is for the first method is of the form
/a/b/{parameter}?start=1 &
end=100 & name="some value"
and for the second method it is
/a/b/{parameter}
When i run the code it gives a conflict.
Can anyone please suggest me how these can be configured for the methods and also to make the query paramters OPTIONAL?
Thanks

This should work fine:
#GET
#Path("/a/b/{parameter}")
public Response get(#PathParam("parameter") String parameter, #QueryParam("start") Integer start, #QueryParam("end") Integer end, #QueryParam("name") String name) {
// switch here according to the values received. All are optional and non-sent are nulls here
}
If in the future you will have default values you can add them inline like this (for the name query param for example):
#DefaultValue("some-name") #QueryParam("name") String name

Related

Limit to number of arguments in a controller method in NinjaFramework?

I'm using NinjaFramework 6.0, tried adding a 10th #Param to my controller method and now I get "No suitable method found for with(Controller[...]Index)" error compiling the Routes.java.
My method looks like this:
public Result personIndex(
#Param("ssn") Optional<String> ssn,
#Param("dodId") Optional<String> dodId,
#Param("firstName") Optional<String> firstName,
#Param("middleName") Optional<String> middleName,
#Param("lastName") Optional<String> lastName,
#Param("birthday") Optional<String> birthday,
#Param("branch") Optional<String> branch,
#Param("rateRank") Optional<String> rateRank,
#Param("status") Optional<String> status,
#Param("page") Optional<Integer> page) { ... }
If I remove one of the params then everything will compile and work. Is this a hard limit? Should I encapuslate these into some sort of form / dto object?
--
This appears to be a problem when using this type of Route configuration:
router.GET().route("/persons").with(PersonController::personIndex);
If I switch to the 'old' way it works fine:
router.GET().route("/persons").with(PersonController.class, "personIndex");
While browsing Ninja docs (http://www.ninjaframework.org/documentation/basic_concepts/routing.html), I noticed the following text
The class ninja.ControllerMethods defines the various interfaces that are acceptable method signatures for Java 8 lambda expressions. A controller method returns a ninja.Result and has anywhere from 0 to 12 arguments. If you need more than 12 arguments, you can fallback to Ninja’s legacy routing strategy of Class + “method”.
Not sure if something changed from 6.0 version, but 10 params should work.

#Path in rest-easy with variable?

I am using rest-easy and I want my #Path annotation to obtain it's value from a variable (mayabe a system parameter).
Eg:
#Path(someVar)
#GET
#Produces(MediaType.TEXT_XML)
public String retrieve() {
}
I tried reading and got to know that Path must be a constant value.
Is something like above possible in rest easy ??
Annotations are processed on compile time. You cannot use a variable as an annotation parameter.
You can pass variable value in URL, something like below example
so your URL will be /book/some_isbn_code and the getBook method will receive isbn value in id field.
#Path("/book/{isbn}")
public String getBook(#PathParam("isbn") String id) {

Spring, middle score in request parameter

Is there a way to map a query parameter with a middle score using requests in spring?
I have no problem binding single worded parameters doing this:
Uri example: http://localhost:8080/test/?product=hotels
public class CitiesRequest{
private ProductType product;
public ProductType getProduct() {
return this.product;
}
public void setProduct(String product) {
this.product = product;
}
}
But I'd like to be able to receive parameters like this:
http://localhost:8080/test/?product-type=hotels
As Misha stated it is syntactically incorrect to have a variable name with a hyphen in Java. But Spring is fine with that and allows you to specify a parameter name (in the request) different from the variable name (in java code). For exemple, when using RequestMapping driven controller, one can write :
#RequestMapping("/test")
public ModelAndView getProduct(
#RequestParam("product-type") String productType) {
...
}
That way, getProduct will be called for a url like http://localhost/test?product-type=hotels and the parameter productTypewill receive the value hotels. And all is still purely declarative.
By default, Spring maps the query parameter key to the name of the Java variable. However, it's syntactically incorrect to have a variable name with a hyphen in Java, which explains why you're finding it particularly difficult to get Spring to set the parameter's value for you.
One workaround that might work is to just have a Map<String, String[]> parameter to represent all of the parameters. Then Spring doesn't have to map any query parameters to variable names, so the hyphenated name might end up in that map of all parameters. It may not be as comfortable as pre-split parameter objects, but it might get the hyphenated keys.
Another solution might be to configure the WebDataBinder, which controls how data from HTTP requests are mapped onto your controller's request parameters. But that's a whole can of worms, especially if you're just starting out with Spring. You can read more about it in the documentation under "data binding".

Can RestEasy choose method based on query params?

I've started working with RestEasy and I've come across a problem that I can't seem to find an answer to. If I have 2 methods that both resolve to the same path (in this case /path1/path2/path3), but they both have a different number of query parameters, will RestEasy be able to determine which method to use?
#GET
#NoCache
#Produces({
MediaType.APPLICATION_JSON
})
#Path("/path1/path2/{path3}")
public String getResults1(
#PathParam("path3") String path3,
#QueryParam("query1") #DefaultValue("") String query1,
#QueryParam("query2") String query2,
#QueryParam("query3") #DefaultValue("25") int query3) {
...
}
#GET
#NoCache
#Produces({
MediaType.APPLICATION_JSON
})
#Path("/path1/path2/{path3}")
public String getResults2(
#PathParam("path3") String path3,
#QueryParam("query1") #DefaultValue("") String query1,
#QueryParam("query2") #DefaultValue("5") Integer query2) {
...
}
I've done some testing and yesterday it seemed that everything was working perfectly and that it could choose the right path, but now today I'm starting to see it take the wrong path each time.
Is this something that should be handled, or should I just suck it up and put it in 1 method and do the check myself?
No, you should be handling this in the method. If conflicting resources are found it is implementation independent which method will be matched.
Take a look at your example again:
If you submitted query1 and query2 how would it know if you wanted the method with 2 query parameters or the method with 3 query parameters and you wanted it to default the 3rd to it's default value?

Is it possible to configure JAX-RS method with variable number of URI parameters?

is it possible to configure GET method to read variable number of URI parameters and interpret them either as variable argument (array) or collection? I know query parameters can be read as list/set but I can't go for them in my case.
E.g.:
#GET
#Produces("text/xml")
#Path("list/{taskId}")
public String getTaskCheckLists(#PathParam("taskId") int... taskId) {
return Arrays.toString(taskId);
}
Thanks in advance
If I understand your question correctly, the #Path annotation can take a regular expression to specify a list of path components. For example, something like:
#GET
#Path("/list/{taskid:.+}")
public String getTaskCheckLists(#PathParam("taskid") List<PathSegment> taskIdList) {
......
}
There's a more extensive example here.
I am not submitting this as an answer as it is merely an edge case on the currently accepted answer which is what I've also used.
In my case (Jersey 1.19) /list/{taskid:.+} would not work for the edge case of zero variable parameters. Changing the RegEx to /list/{taskid:.*} took care of that. See also this article (which seems to be applicable).
Moreover, upon changing the regexp to cardinality indicator to * (instead of +) I also had to deal programmatically with the case of empty strings as I would translate the List<PathSegment> into a List<String> (to pass it into my DB-access code).
The reason I am translating from PathSegment to String is that I didn't want a class from the javax.ws.rs.core package to pollute my Data Access Layer code.
Here's a complete example:
#Path("/listDirs/{dirs:.*}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response listDirs(#PathParam("dirs") List<PathSegment> pathSegments) {
List<String> dirs = new ArrayList<>();
for (PathSegment pathSegment: pathSegments) {
String path = pathSegment.getPath();
if ((path!=null) && (!path.trim().equals("")))
dirs.add(pathSegment.getPath());
}
List<String> valueFromDB = db.doSomeQuery(dirs);
// construct JSON response object ...
}

Categories