JAX-RS PUT method. How does the input media declared by the #Consumes annotation get injected in the method's parameter? - jersey

I have the following method declared in my resource class.
#Path("{id:\\d+}")
#PUT
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response putPerson(#PathParam("id") long id, Person person) {
logger.debug("Going to update the person with id: {} to name {} age {} and salary {}", id, person.getName(), person.getAge(), person.getSalary());
db.put(id, person);
return Response.noContent().build();
}
Here I understand that my {id} path value does get injected in the id parameter due to the #PathParam annotation. But I am curious how does the input media declared by the #Consumes annotation get injected in the person parameter? I am wondering because there are no annotation declared to inject any value into the person parameter.
I know that the media does get injected because my logger statement does print the correct values.
Is this inject process documented somewhere in the Jersey user manual or any JavaDocs?

I did find the answer in the Jersey User Guide for version 2.31 release in section 7.1. It reads the following.
Unlike method parameters that are associated with the extraction of
request parameters, the method parameter associated with the
representation being consumed does not require annotating. In other
words the representation (entity) parameter does not require a
specific 'entity' annotation. A method parameter without an annotation
is an entity. A maximum of one such unannotated method parameter may
exist since there may only be a maximum of one such representation
sent in a request.

Related

Access function parameter by annotation in AOP (AspectJ)

I have a function under class MyController:
#RestController
#RequestMapping(value = "/api/service")
public class MyController {
#PostMapping(value = "add_person")
public MyResponse addPerson(#RequestBody Person person) {
// ...
}
#PostMapping(value = "add_person_2")
public MyResponse addPerson(#PathVariable(value = "person_age") Int age, #RequestBody Person person) {
// ...
}
}
I have setup AspectJ in my project to have a AOP logic to run whenever those two addPerson(...) method above is called:
#Around("execution(public MyResponse addPerson(..))")
public void around(ProceedingJoinPoint joinPoint) {
// NO matter which addPerson(...) is executing, I am only interested in the
// parameter value annotated with #RequestBody.
// How can I access the parameter that passed in addPerson(...) & is annotated with
// #RequestBody through ProceedingJoinPoint ?
}
My question is mentioned in above code comment. I wonder how can I access the parameter annotated with #RequestBody in my AOP function? I don't want to check parameter type or name, but interested to know how to access parameter by checking the annotation through ProceedingJoinPoint. Is it possible?
I do not want to mark this question as a duplicate because it is no exact duplicate, but my answer here should answer the question about how to
match an annotated parameter at any position,
get the annotation + the parameter value itself.
The linked answer uses a #Before advice. If you want to somehow replace the value by another one in an #Around advice when calling proceed() this is also possible, but was not asked here and my request for seeing more of the advice method body was also ignored.
If you want to limit to annotated Person parameters, you would have to use the fully qualified class name my.package.Person instead of the * inside (*) and do the corresponding cast after accessing the parameter in the advice body.
In my comment I also asked if the parameter has a fixed relative position in the parameter list such as first, last or second/third from left/right. If the OP would have confirmed such a fixed relative position, reflection would not be necessary and the corresponding parameter could be bound to an advice method parameter directly via args() pointcut designator. This would be quite elegant and eliminate the need to loop over getArgs() or over a two-dimensional array of parameter annotations.

#ModelAttribute vs #RequestBody, #ResponseBody

#ModelAttribute
RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method =
RequestMethod.POST)
public String processSubmit(#ModelAttribute Pet pet) { }
http://.../?name=Something&age=100
public String doSomething(#ModelAttribute User user) { }
#RequestBody
#RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(#RequestBody Contact contact){ }
{ "name": "Something", "age": "100" } in request body
public String doSomething(#RequestBodyUser user) { }
#ModelAttribute will take a query string. so, all the data are being pass to the server through the url
#RequestBody, all the data will be pass to the server through a full JSON body
Now which one is the best approach ???
If both are for same purpose to bind to the bean..which one is the best practice or widely used as standard practice?
Both handles multi-part file and does it both have equivalent options with one another ?
https://javabeat.net/spring-multipart-file-upload/
How do i upload/stream large images using Spring 3.2 spring-mvc in a restful way
Does any one of them has lesser capabilities then the other one? Like length limitations, method limitations. Drawbacks
Which one is more secured in terms of security ?
As the javadoc suggests, it's the usage that sets them apart, i.e., use #ModelAttribute if you want to bind the object back to the web view, if this is not needed, use #RequestBody
#RequestBody
Usecases : Restful controllers (ex: produce and consume json/xml, processing direct document download requests, searching for stuff, ajax requests )
As the name suggests the if a method argument is annotated with #RequestBody annotation Spring converts the HTTP request body to the Java type of the method argument.
Is only allowed on method parameters (#Target(value={ PARAMETER}))
The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request.
works for Post and not Get method.
#ModelAttribute
Usecases : web app controllers (ex: binding request query parameters, populating web views with options and defaults)
Uses data binders & ConversionService
Is allowed on methods and method params(#Target(value={METHOD, PARAMETER}))
Useful when dealing with model attributes for adding and retrieving model attributes to and from the Srping’s Model object
When used on METHODS, those methods are invoked before the controller methods annotated with #RequestMapping are invoked
binds a method PARAMETER or method return value to a named model attribute & the bound named model attributes are exposed to a web view
binds request query parameters to bean
For more information on Data Binding, and Type Conversion refer: https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/core.html#validation

Map JAX-RS #PathParam to POJO Constructor With Annotations

I want to create an endpoint which has a PathParam that automatically calls the constructor of an object to be injected, which has a constructor of a String argument. To spell it out in code:
Here is the resource
#GET
#Path("/{apiVersion}" + "/item")
public Response version(#PathParam("apiVersion") APIVersion apiVersion) {
return Response.ok().build();
}
I want the String to automatically be used in a call to the APIVersion constructor. In the APIVersion class
public APIVersion(String apiVersion) {
this.versionString = apiVersion;
}
Is it possible to do with only access to annotations? I do not have access to the ResourceConfig.
Yes, this is possible, without any annotations other than #PathParam, so the example you've given should work as-is. See https://jersey.github.io/documentation/latest/jaxrs-resources.html#d0e2271 (emphasis mine) :
In general the Java type of the method parameter may:
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) and
java.util.UUID.fromString(String));
Have a registered implementation of
javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that
returns a javax.ws.rs.ext.ParamConverter instance capable of a "from
string" conversion for the type. or
Be List, Set or SortedSet, where T satisfies 2 or 3 above.
The resulting collection is read-only.

POST / GET Request Param Validation in Spring Boot

I am using spring boot. I want to validated the POST request params. So I have gine through #Validated annotation but this require creating a different class for Every API. How should I write my code?
As for example, this is my api
#RequestMapping("/tags/{tagId}/{tagParentId}")
public Response<Demo> a(#PathVariable int tagId, #PathVariable int tagParentId){
... code
}
#RequestMapping("/data/{courseId}/{instId}")
public Response<Demo> b(#PathVariable int courseId, #PathVariable int instId){
... code
}
How should I change my code to add params validation for there API's such that I do not need to create two different validation class? Just one class and then I can add different functions for different API's.
#Validated should be used, to check that a parameter is syntactical correct.
As you are using int values, this is already done by spring.
If tagId is not a valid int, the client will already receive a Http error code.
The validation, whether there is a tag with the given tagId is implicitly done in your code, you do not need an additional validator for that.
If you read tags for example from the database, and you cannot find a tag for the tagId, you should
return new ResponseEntity(HttpStatus.NOT_FOUND);
from your controller method.
You may need to change the return type of your controller method to a common superclass or just to Object, to allow returning the ResponseEntity.
Its also possible to throw exceptions in the controller methods and to configure spring to return a regarding HttpStatus.
See exception-handling-for-rest-with-spring

Spring Controller fetch query parameter for a wrapper request class

I am trying to build RESTful web service by using spring 4.0
I have a controller:
#Controller
#RequestMapping("test")
public class Controller{
#RequestMapping("fetch",method=RequestMethod.GET)
#ResponseStatus(value=HttpStatus.OK)
#ResponseBody
public ResultResponse fetchController(ResultRequest req){
if((req.getName).equals("John"))
return new ResultResponse(100);
else
return new ResultResponse(0);
}
}
and my ResultRequest.class
public class ResultRequest{
private String name;
//getter,setter
}
If I hit the url to //host//contextPath/test/fetch?name=John
the controller will return the object ResultResponse(100)
my question is, there no #RequestParam or other annotation in the request parameter,
how does the spring controller know to set the query parameter "name" as the property of wrapper class
ResultRequest ?
Thanks
Spring uses implementations of an interface called HandlerMethodArgumentResolver for resolving arguments to pass to handler methods, ie. methods annotated with #RequestMapping.
One of these is a ModelAttributeMethodProcessor. Its javadoc states
Resolves method arguments annotated with #ModelAttribute and handles
return values from methods annotated with #ModelAttribute.
Model attributes are obtained from the model or if not found possibly
created with a default constructor if it is available. Once created,
the attributed is populated with request data via data binding and
also validation may be applied if the argument is annotated with
#javax.validation.Valid.
When this handler is created with annotationNotRequired=true, any
non-simple type argument and return value is regarded as a model
attribute with or without the presence of an #ModelAttribute.
Spring registers two objects of this type. One to handle parameters annotated with #ModelAttribute and one to handle ones without.
Further reading:
Form submit in Spring MVC 3 - explanation
An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the #RequestBody or the #RequestPart arguments

Resources