Jersey : Is it possible to specify multiple values in #DefaultValue() annotation - java

I am playing around with Java API for RESTful Web Services (JAX-RS) ,
and encountered #DefaultValue annotation in Jersey implementation of JAX-RS.
Here is the code snippet
#GET
#Path("/query")
public Response getUserWithQueryParams(
#DefaultValue("defaultId") #QueryParam("from")String from,
#DefaultValue("defaultName") #QueryParam("to") String to,
#DefaultValue("mobileNo")#QueryParam("orderBy") List<String> orderBy
){
My third argument is of List<String> which can have multiple values
for example I explicitly pass the parameters
users/query?from=100&to=200&orderBy=age&orderBy=name
Now my third argument have values [age,name] ,
but if i don't pass any explicitly parameter then Is there any way to set multiple default values . ?

This won't work how you want it to. If the object is type List it will have a single value inserted in the list. The object in the list will be the value of your default value for the list. Check this out Why not try checking if orderBy == null if it does then add your default values to orderBy?

Related

Using a value as an argument into another value in Thymeleaf

So lets say I have a #ModelAttribute of userCredentials which is a List<String> object.
and I have another ModelAttribute of type Map<String,String> of roles.
I can access them separately in HTML using Thymeleaf with:
${userCredentials.contains('<Hardcoded-value>')}
The problem i want the hardcoded value replaced and to use for example:
${userCredentials.contains('roles.client')}
Do you know how can i successfully use a model attribute as a parameter to the other model attribute. It works with the hardcoded values
You can use Thymeleaf pre-processing:
${userCredentials.contains(__${roles.get('client')}__)}
Thymeleaf executes the preprocessing part in a first pass. So it will replace what is there with:
${userCredentials.contains(<result of roles.get() call here>)}
And then execute the template rendering.

How to pass list of parameters in rest get call (like filter object in eCommerce )

In my application, there is a requirement of getting data based on some parameters.
I just want to what is the better way to do.
The one way is, I can pass the list of parameters as a path variable.
The second way is, I can pass the request body, I think it is vague and I am not sure it is possible or not.
You can find the code below:
#GetMapping("/cities/{cityName}/latitude/{latitude}/longitude/{longitude}/cityId/{cityId}/street/{street}")
public ResponseEntity<ResponseContainer<CityDto>> getCityByCityNameOrLatitudeAndLongitude() {
}
I just want to know how can I achieve the same.
There is one more question, E-commerce companies have big filter criteria so how they are achieving.
Although there is no hard & fast rule but I generally avoid sending a body in GET request because it's a bad design. You should also refer to this SO Post which contains discussion about using body in GET request. It's an opinionated post and there is no clear YES or NO, but you will get an idea.
HTTP GET with request body
You can either use Path params or query params depending on what those field represent.
Regarding the difference or which to use when I am quoting this answer, which mentions that although there is no hard rule but generally it's better to use params which can uniquely identify the resource as Path param (e.g. id, name etc) and if your param is supposed to do something like filtering/sorting e.g. records after Jan 1 2019 , then go for query param.
Also personally in one of my APIs (which performs filtering), I am using a generic query param, where I pass on JSON object in my query. So basically my API needs to search an object based on variable/multiple attributes. E.g. I have in my db , objects which have certain voltage, current, size etc. values. So, request might come with a combination of 1 or more. So to keep my API flexible, I have provided a query param which can accept JSON object.
So I make a request like this:
{{SERVER}}/api/search?query={voltage:12V,size:10}
And in my API, I can convert this json object to corresponding POJO:
#GET
#Path("/search")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response search(#QueryParam("query") String queryParam) throws Exception
{
Myobj obj = new Gson().fromJson(queryParam, Myobj.class);
// rest of code
By passing the parameters in the path, you are restricting yourself to extend your API. If you want to extend your API, for example, if you want to filter with criteria as Street1 (or) Street2 then your path wouldnot support it and it will force you to update your API. It is better to pass criteria objects in the body or url parameter. Amazon India is passing criteria like below. I have choosen mobiles with criteria as Manufacturer = Samsung or MI, Storage as 8gb or 4gb and they simply appended the criteria in the query parameters.
There is a third way, Request Params.
#GetMapping
public ResponseEntity<ResponseContainer<CityDto>> getCityByCityNameOrLatitudeAndLongitude(#RequestParam("cityName") String cityName, #RequestParam("latitude") String latitude, #RequestParam("longitude") String longitude){
// Your code
}
For more: 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting #RequestParam's required attribute to false (e.g., #RequestParam(value="id", required=false)).
https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-ann-requestparam

Passing list of enum values as HTTP query parameters

I want to pass list of enum values as HTTP query parameter. The entry point of the server side looks like this:
#GET
#Path("/getMyResult")
public MyResultType getMyResult(#QueryParam("me") final List<MyEnum> myEnums)
This cannot be modified. Consider MyEnum contains values MyValue1, MyValue2, MyValue3 and MyValue4. (MyResultType is not relevant for this question.) Passing only one value, as follows, works fine (which is a bit strange for me):
http://localhost/getMyResult?me=MyValue1
However, passing list of elements this way:
http://localhost/getMyResult?me=[MyValue1,MyValue3,MyValue4]
or this way:
http://localhost/getMyResult?me=MyValue1,MyValue3,MyValue4
or this way:
http://localhost/getMyResult?me=["MyValue1","MyValue3","MyValue4"]
does not work, it throws exception something like this (error message to the first option):
RESTEASY001720: Unable to extract parameter from http request: javax.ws.rs.QueryParam(\"me\") [...]
No enum constant com.mycompany.myapp.MyEnum.[MyValue1,MyValue3,MyValue4]
Can anyone tell me how to pass a list of MyEnum elements as HTTP GET query parameter? Thank you!
For this (and other cases you need to pass a List) you must insert name of the parameter for each element.
In this way:
http://localhost/getMyResult?me=MyValue1&me=MyValue3&me=MyValue4

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

How to pass generic List<User> to restful web services

I have the requirement to create the search operation using restful web services, i.e, using #GET. The method signature takes String and List as input argument and returns List.
public Generic List <Employer> getAllEmployer(String employeeName, Generic List <employeeLocation>);
Kindly request if someone could describe on how to implement the same. Should I use query param or path param or form param. I need to return the List of employer in json format.
if the employee locations are just string, pass them as comma seperated values and spring will take care of converting it to list. I would rather suggest just to have it as a pathparam rather than having it as a query param.
This is just my opinion but I think that the "RESTful" way to pass multiple parameters with the same name would be to a MultiValueMap.
Spring and Jersey both have implementations of MultiValueMap however, below is an example of a spring implementation:
#RequestMapping(method = RequestMethod.GET, value = {"/employer/_search"})
public List<Employer> search(#RequestParam MultiValueMap<String,String> params) {
return someService.search(params);
}
They way that you would call this url would then become:
/employer/_search?employeeName=name&location=1&location=2&location=3
Then behind the scenes spring will create the MultiValueMap for you which is a Map<String,List<String>> where any parameters with the same name are put into the same list.

Categories