I've got super specific logic of mapping content of the body to bean. I tried to use ParamConverterProvider but it works only for #PathParam, #QueryParam and etc.
Is there simple way of customizing mapping body to bean?
In jersey it uses provided reader types to convert from the request body to arbitrary types. You'll want to implement MessageBodyReader with your bean.
Be sure to annotate your reader with #Provided and make sure it's explicitly registered in your ApplicationConfig or in a package that will be automatically scanned.
You shouldn't annotate your method that takes in the bean:
#Get
...
public Response doGet(MyBeanType bean) {
...
}
another (dirty!) Approach could be to accept an Object and transform the object into your needed Pojo-Structure.
This of course depends of the structure which is handed in. Just debug to find out how your object looks like.
#Get
public Response doSome(Object o){
if (o instanceof List) { .... }
}
Anyway, this should better be done with a MessageBodyReader as John H suggested!
Related
I am trying to document an already existing application using javax.ws.rs annotations to define what headers (#HeaderParam) and parameters (#QueryParam) a specific endpoint needs. This information would them be used to generate a swagger page for the application.
public Response SampleFunction(#RequestBody(...),
#QueryParam(...),
#HeaderParam(...),
#HeaderParam(...),
#HeaderParam(...),
etc etc etc){
return doStuff()
}
I have identified a set of "#HeaderParam" which are required for all endpoints.
I need to know if there is any way for me to define the #HeaderParam only once and use that definition for all endpoints and, since this is an already existing application, I need to do this change without any major code refactorization.
We believe to have found a solution for this matter.
By declaring the #HeaderParam globally they appear for all endpoints without having to repeat the declaration for each endpoint.
Something like this:
#Path("/")
public class myClass{
#HeaderParam("Parameter_one")
#Parameter(example = "example_one)
Type parameter_one
#HeaderParam("Parameter_two")
#Parameter(example = "example_two)
Type parameter_two
public Response SampleFunction(#RequestBody(...),
etc etc etc){
return doStuff()
}
}
In this particular case, Parameter_one and Parameter_two will become available on the Swagger page for all endpoints.
I have seen similar answer here:
Spring MVC: Complex object as GET #RequestParam
Spring map GET request parameters to POJO automatically
I really can't find document of this because this auto mapping is not even done by any annotation. (it doesn't even need #RequestParam in fact)
1) so far I only see simple mapping, the object contain all primitive data, how about if my request is a complicated JSON object which contain several level of attributes (a object contain other objects)? Will the auto-mapping still work?
2) so far I only see Spring controller can take in one auto-map object, can I let it auto-map more than one object? For example:
public #ResponseBody List<MyObject> myAction(MyObject myObject,
MyObject2 myObject2) { ... }
Anyone know where is the document to describe how the mapping work behind the scene? Based on my second question, if Spring allow to do such thing, what if I have same attributes name in MyObject and MyObject2, how the mapping will do?
If you do things like this:
public #ResponseBody List<MyObject> myAction(#RequestBody MyObject myObject) { ... }
Of course you can only have one body in your http request.
As long as you have Jackson in your classpath (spring boot will add this automatically) your objects will be marshalled correctly.
If the JSON in your body is incorrect you will get a 400 (Invalid Request) returned.
Thanks to #RestController I don't need to add annotation #ResposneBody, cause spring knows that it is rest controller, and he will not generate view, but instead it will return json object.
Unfortunately there is one more annotation related to this topic. It is #RequestBody, when controller method accept json object as a parameter. And it will have to be pointed before that parameter.
My question is there a way to get rid of that annotation (#RequestBody).? If my controller is rest controller (#RestController instead of regular #Controller) it should be demanded from spring?
No, you'll have to specify #RequestBody. A Java method can have only a single return value, and so the #ResponseBody is unambiguous, but there are multiple possible ways that mapped controller parameters might be interpreted (in particular, using #ModelAttribute with form encoding is a very common alternative to #RequestBody with JSON), and you'll need to tell Spring how to map the incoming request.
Is it possible to get a JAX-RS implementation such as RESTEasy to automatically construct an object containing only #*Param annotations, such as #MatrixParam? I have the following class representing pagination:
public class Pagination {
#MatrixParam("after") public String afterKey;
#MatrixParam("from") public String fromKey;
#MatrixParam("to") public String toKey;
#MatrixParam("before") public String beforeKey;
#MatrixParam("count") public int count;
}
I'd like to pass it to JAX-RS methods such as this:
#GET
#Produces("text/html")
Response asHtml(Pagination pagination);
I was hoping RESTEasy would call the default constructor and then inject the field values, but I get a "Could not find message body reader" error. Obviously, there is no message body, and adding a dummy String constructor did not help. Do I need to create my own #Provider for this? If so, could such a thing be made generic and leverage the built-in #*Param injection features?
I know this a bit old subject, but JAX-RS 2.0 has #BeanParam annotation that does this.
#GET
#Produces("text/html")
Response asHtml(#BeanParam Pagination pagination);
From an answer to a similar question, there's a RESTEasy-specific annotation, #Form, that allows this:
This is a RESTEasy specific annotation that allows you to re-use any #*Param annotation within an injected class. RESTEasy will instantiate the class and inject values into any annotated #*Param or #Context property. This is useful if you have a lot of parameters on your method and you want to condense them into a value object.
The #Form annotation goes on the resource method parameter or resource field, not the value object class:
#GET
#Produces("text/html")
Response asHtml(#Form Pagination pagination);
Other implementations may require an entity provider. From the JAX-RS spec (JSR-339):
3.3.2.1 Entity Parameters
The value of a parameter not annotated with #FormParam or any of the annotations listed in Section 3.2, called the entity parameter, is mapped from the request entity body. Conversion between an entity body and a Java type is the responsibility of an entity provider, see Section 4.2. Resource methods MUST have at most one entity parameter.
I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}