#Path in rest-easy with variable? - java

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) {

Related

Default/Constant values for POST/PUT arguments with Retrofit

Using the Retrofit REST Client library from Square, is there anyway of providing default/constant values for POST/PUT fields in a call.
I know about including constant query parameters by simply including them in the path, but this work for Body parameters.
I have an API that looks similar to:
POST /api/create
type=constanta&value={value}
POST /api/create
type=constantb&value={value}&otherValue={otherValue}
where the second variant requires an additional argument to be supplied. Rather than having a single java method that took all three arguments, I was hoping to be able to elide the constants from the method call, something like:
create(String value);
create(String value, String otherValue);
and have retrofit inject the type argument constant.
Given that adding #FormUrlEncoded can be added to modify how the body is encoded, if it's not natively supported by Retrofit, is there anyway of adding my own annotation and injecting such default values? ( It doesn't appear that RequestInterceptor allows one to modify the body.. ).
Maybe one option would be to send an object, which encapsulates all your values, instead of all string values separately? The object would implement your default values.
For example, you could create a class:
public class CreateObject {
private String type = "constant";
private String value;
private String otherValue;
public CreateObject(String value, String otherValue) {
this.value = value;
this.otherValue = otherValue;
}
}
Your class handles your constant. You could just set it to a default value "constant", like I did above, or set it on the fly in the constructor.
Now all you've to do is to create the object with the values and make the request with Retrofit. Instead of using the string values directly, just pass the object. Your interface could look like this:
public interface CreateService {
#POST("/api/create")
void create(#Body CreateObject create, Callback<CreateObject> cb);
}
The request implementation like this:
CreateObject create = new CreateObject("value", "otherValue");
createService.create(create, new Callback<CreateObject)() {…});
This should include all three of your values in the request body, if they are set. If a value is null, it won't be included in the request body. Based on your two examples above, you would now only need one interface method. Which values are sent is based on the createObject you pass on. For example, if you set otherValue as null, it won't be part of the request body.
My examples were modified from: https://futurestud.io/blog/retrofit-send-objects-in-request-body/
Is it possible for you to use Guava or Java 8 Optional as second argument in method? Then if that argument will be absent you can just ignore it

Regarding REST Path Conflict

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

Spring RequestMapping: differentiate PathVariable with different types

Is there a way to tell Spring to map request to different method by the type of path variable, if they are in the same place of the uri?
For example,
#RequestMapping("/path/{foo}")
#RequestMapping("/path/{id}")
if foo is supposed to be string, id is int, is it possible to map correctly instead of looking into the request URI?
According to the spring docs it is possible to use regex for path variables, here's the example from the docs:
#RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(#PathVariable String version, #PathVariable String extension) {
// ...
}
}
(example taken from http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-patterns )
Judging from that, it should be possible to write something like this for your situation:
#RequestMapping("/path/{foo:[a-z]+}")
#RequestMapping("/path/{id:[0-9]+}")

Defining custom parameter types with JAX-RS to return data by identifier

I am new to Jersey, and I discovered that we can define our own parameter types to handle other types than string, as dates or boolean for instance.
I will work with an ORM to store the data in a database, so that I will be able to map an identifier to an instance of a class, let's say to a User.
Is it a good practise to define a param class which would handle the user id given in parameter (path or query for instance), and return the instance of User corresponding to the id?
If your param is directly mappable to a primitive type then there's no need to define your own. It sounds like you want to accept a user ID as a param, which is likely to be a long, int or String. All of these are automatically mapped.
For example;
#Path("/")
public class UserService {
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/{id}")
public User getUser(#PathParam("id") String id) {
//Your implementation here
}
}
Well, lets take some example:
stackoverflow.com/users/1235336/
Here we have the path with usedId in it. And if we proceed the link (execute a GET request), we will get the some user enity in response.
So defining a user id as a path parameter and returning some user instance is kind of normal practice.

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