#QueryParam or HttpServletRequest in java - java

I have resource class - UserResource interface and I have defined an endpoint as getUsers.
Now I want to filter these users based on users status - (Active, Inactive) and its not mandatory so if I does not pass the status it will fetch all the users.
Now the question is should I pass this as #QueryParam or get it from
HttpServletRequest - httpServletRequest.getParameter("Status").
Which one from the above two is best way and in what scenario I should use which one.
1. First way is pass the status as query param and define in the resource file itself. Here UserResource is the controller interface or resource class. In getUsers method has #QueryParam.
import javax.ws.rs.core.Response;
#Path(/user)
public interface UserResource{
#GET
#Path("/")
#Produces({ MediaType.APPLICATION_JSON })
Response getUsers(#QueryParam("status") String status);
}
#Component
Public class UsersResourceImpl implement UserResource{
public Response getPlan(String status){
String userStatus = status;
// some logic
}
}
2. Second way is get the query param from HttpServletRequest. so I have
autowired the HttpServletRequest and getting the query param from the
httpservletrequest.
import javax.ws.rs.core.Response;
#Path(/user)
public interface UserResource {
#GET
#Path("/")
#Produces({ MediaType.APPLICATION_JSON })
Response getUsers();
}
import javax.servlet.http.HttpServletRequest;
#Component
Public class UsersResourceImpl implements UserResource{
#Autowired
private HttpServletRequest httpRequest;
public Response getPlan(String status){
String status = httpRequest.getParameter(status)
// some logic
}
}
'''

Well, I honestly don't see any appealing reason to avoid using the #QueryParam annotation given that you need the value from a query parameter.
Some benefits of using #QueryParam that I can think of:
The #QueryParam annotation will automatically bind the value(s) of a query parameter to a resource method parameter, resource class field, or resource class bean property. So you won't need to extract and parse parameters manually, once you respect some rules described in the documentation:
The type T of the annotated parameter, field or property must either:
Be a primitive type
Have a constructor that accepts a single String argument
Have a static method named valueOf or fromString that accepts a single
String argument (see, for example, Integer.valueOf(String))
Have a registered implementation of ParamConverterProvider JAX-RS extension SPI that returns a ParamConverter instance capable of a "from string" conversion for the type.
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3 or 4 above. The resulting collection is read-only.
#QueryParam can be combined with #DefaultValue to define a default value for the parameter in case it's not present in the request.
If multiple endpoints support the same query parameters, you could aggregate them in a class and receive an instance of such class as a #BeanParameter.

Go with annotations (i.e #QueryParam) that's why we chose such framework , remember convention over configuration.

Related

Get request mapping object in spring interceptor, to get actual url string pattern

It might be hard to explain why, but I have this situation where I need to get the request url mapping string of currently requested url.
Like if I have a GET URL as "/Test/x/{number}"
I want to get "/Test/x/{number}" not "/Test/x/1"
can I get the actual declared url string in interceptor?
If this is possible how can I achieve this
You can implement a HanderInterceptor to intercept, pre or post, request and introspect the method being called.
public class LoggingMethodInterceptor implements HandlerInterceptor {
Logger log = LoggerFactory.getLogger(LoggingMethodInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod method = (HandlerMethod) handler;
GetMapping mapping = method.getMethodAnnotation(GetMapping.class);
log.info("URL is {}", Arrays.toString(mapping.value()));
return true;
}
}
This will output, URL is [/hello/{placeholder}]
Full example can be found here, https://github.com/Flaw101/spring-method-interceptor
You could add more logic to introspect only certain methods, certain types of requests etc. etc.
I think that you can get it with reflection and getting #RequestMapping anotations.
for example when you use
#RequestMapping(value = "/Test/x/{number}", method = RequestMethod.GET)
the value is what you are looking for if I got it right!
You only must find the controller class type.
Its possible I think but I didn't test it.
Check this:
In a Spring-mvc interceptor, how can I access to the handler controller method?
First it may be solved if the HandlerMethod was right but if you get cast error then you must get the controller class [I think].
When you get the controller class then you can looking for the method with according #RequestMapping annotation.
So
1- Find the controller class type
2- Search all methods with in the class by reflection
3- Check method annotations with specified url and specified method [GET / POST]
4- select the best candidate
If you have more than two URL parameter this method is not good!

JAX-RS validation messages when in interface

I have a dropwizard 1.0.6 application. I want to put all JAX-RS and validation annotations on an interface and then register my resource to implement this interface, similar to:
#Path("/user")
#Produces(MediaType.APPLICATION_JSON)
public interface UserEndpoint {
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
Response createUser(
#FormParam("username") #NotEmpty #Email String username,
#FormParam("password") #Size(min=4) String password);
}
and the resepective resource:
public class UserResource implements UserEndpoint {
public Response createUser(String username, String password) {
//my logic here
}
}
This works amazingly, except for the validation messages in the error responses, which have become:
createUser.arg0 not a well-formed email address
while I would expect them to be:
form field username not a well-formed email address
UPDATE:
If I add the JAX-RS and validation annotations straight to UserResource, then the validation message is what I would expect: it reports the name of the parameter as specified in the #FormParam annotation. This is what I want to achieve, but having the annotations in the interface.
Annotations are not inherited, unless they are annotated with #Inherited.
Per the Java Language Specification
Annotation inheritance only works on classes (not methods, interfaces, or constructors)
So it is up to the code that wants to use the annotations if it will check the parent class/interface for annotations.
In other words you will need to contribute to Dropwizard to make it search annotations from parent classes/interfaces
the real name of the parameters is not available for the JVM at runtime so that's why it is replaced by arg0 , in order to fix this issue you'll had to deal with ParameterNameProvider which will use reflection in order to return a list of String from getParameterNames(Method yourExceptionImpl)

Deserializing abstract class Spring mvc

Let´s say that I have an abstract class A, that class is inside my MainClass, then I have the implementation of this class B and C. Using ModelAndAttribute I render in some scenarios MainClass with B and in others MainClass with C implementation. Both has the same commit method in the controller, so when I request this ModelAndAttribute in the form I´m waiting MainClass with B or C implementation as was render before, but Spring is it´s consider is A all the time "NullValueInNestedPathException, Invalid property, value of nested property is null".
Any idea if Spring has a mechanism to determine which implementation class is receiving?.
I´ve read this http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html and looks promising but I cannot interact or I dont want interact with Jackson about how serialize the entities.
Regards.
Spring will not decide which implementation to instantiate.
You will have to add some code to decide which of the 2 class needs to be initiated
We have similar requirement
we pass the type ClassB or ClassC in request parameter
We have method
#ModelAttribute (value = "mainClass")
public void populateObjectBasedOnRequestParameter (
ModelMap modelMap, HttpServletRequest request)
this method basically reads the request parameter and instantiate the mainClass with correct implementation of class A
For the form submit
#RequestMapping (value = "/{workItemId}", method = RequestMethod.POST, params = "save", consumes = MediaType.ALL_VALUE)
public String commit(
#ModelAttribute ("mainClass")MainClass mainClass,
BindingResult result, Principal principal,
HttpServletRequest request, final ModelMap model) {
when the form is submitted with request parameter
populateObjectBasedOnRequestParameter() this method is executed so the model map has the initiated implementation for Class A when commit() method is executed

JAX-RS How to get a cookie from a request?

Consider the following method:
#POST
#Path("/search")
public SearchResponse doSearch(SearchRequest searchRequest);
I would like this method to be aware of the user who made the request. As such, I need access to the cookie associated with the SearchRequest object sent from the user.
In the SearchRequest class I have only this implementation:
public class SearchRequest {
private String ipAddress;
private String message;
...
And here is the request:
{
"ipAddress":"0.0.0.0",
"message":"foobarfoobar"
}
Along with this request, the browser sends the cookie set when the user signed into the system.
My question is how to access the cookie in the context of the doSearch method?
You can use the javax.ws.rs.CookieParam annotation on an argument of your method.
#POST
#Path("/search")
public SearchResponse doSearch(
SearchRequest searchRequest,
#CookieParam("cookieName") Cookie cookie
) {
//method body
}
The Cookie class used here is javax.ws.rs.core.Cookie but you don't have to use it.
You can use this annotation on any argument as long as is:
is a primitive type
is a Cookie (same as in the example above)
has a constructor that accepts a single String argument
has a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String))
havs a registered implementation of ParamConverterProvider JAX-RS extension SPI that returns a ParamConverter instance capable of a "from string" conversion for the type.
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3, 4 or 5 above. The resulting collection is read-only.
These rules come from the documentation of the #CookieParam annotation as implemented in Jersey, the reference implementation of JAX-RS

How to inject dynamic Bean parameter into Jersey method?

I'm developing a webservice with Jersey 2.0 and Spring.
I want to be able to inject a bean into my methods. Bean parameters can be obtained using #BeanParam. However, I need a 'dynamic' bean injected. I need this bean to contain all of the query parameters passed to the method.
For example, if I make a request GET /posts?title=lorem&date=2011-01-01&tag=game
And I have a method like
#Path('/posts')
public class PostService{
#GET
public Response getAll(#QueryParam("page") int page,
#QueryParam("pageSize") int pageSize,
#BeanParam SearchParameters sp){
sp.getTitle();
sp.getDate();
sp.getTag();
}
}
I might be easier to get a map of query parameters Map<String, String>.
#BeanParam allows to put more injectable parameters into one bean (POJO), so that you do not have so many injectable parameters in the resource method, in resource method constructor or so many injectable fields in the resource class. You can encapsulate them into bean injected with #BeanParam. This deals with parameters like #HeaderParam, #QueryParam and such. But you can also inject ContainerRequestContext, UriInfo, SecurityContext or any other injectable object into your bean.
However, in your case you need to use the map of query parameters because you need all parameters and not only specific parameters known before. In order to get them, you can inject UriInfo and get query parameters from it:
#GET
public Response get(#Context UriInfo uriInfo) {
MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
String myParam = queryParameters.getFirst("myParam");
...
}
Or you can use #BeanParam and inject #UriInfo into a bean.

Categories

Resources