I have a REST service:
#POST
#Path("/shop/{prodID}/{price}")
public Response updatePrice(#PathParam("prodID") Long prodID, #PathParam("price") Double price) {
priceDAO.updatePrice(prodID, price);
return Response.ok().build();
}
If i send number for UI they work great, but if a send empty param (null) I have error:
sitesurl/shop/33/null 404 Not Found
and
Class java.lang.Double can not be instantiated using a constructor with a single String argument
on console.
If null sending as string ("null") we could see NumberFormatException.
Why my service can not parse nullable PathParam?
chrylis if you dont provide any of the path params it would throw a 404 resource not found,
I Agree with Chrylis form param would be a good idea.
Gene then you should ensure while sending the request path params are not null and complying to the resource specifications. for a Long or a double string should not be sent.
Another way of getting rid is you keep the resource spec as String, and manually cast to Long etc..
There is way to handle ParamExcption well. Create a Mapper that implements ExceptionMapper and throw your custom response
Related
I am calling an external API (on which I do not have a control to make any change) using Spring's RestTemplate. The API returns response with an array as response body if the results are found and if not it returns response with String as response body stating "No records found". I am getting an exception when I am getting the no company found message because I typecasted the RestTemplate call to the custom object
ResponseEntity<Student[]> studentDetails = restTemplate.getForEntity(studentUrl, Student[].class);
The above code throws exception when the API returns String message "No records found".
What is the best way to deal with such a scenario?
In that case, you probably may use it like that
ResponseEntity<Object> studentDetails = restTemplate.getForEntity(studentUrl, Object.class);
And then check for the response type and cast the result.
I have a Java Spring API which expects 2 params, a simple String and a object:
#RequestMapping(value = "list", method = RequestMethod.GET)
public ResponseEntity<ListResource> getList(#RequestParam("agentName") String agentName,
#RequestParam("paginationInfo") PaginationInfoList paginationInfo {
//After http request i expect to have here my java Object PaginationInfoList ready to use
}
I'm, trying to send http GET request with Postman but i get this error, then i suppose that i'm not sending the data object "paginationInfo" in the correct way.
"Failed to convert value of type 'java.lang.String' to required type 'com.pippo.prova.test.model.in.PaginationInfoList'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.pippo.prova.test.model.in.PaginationInfoList': no matching editors or conversion strategy found"
Since i can't change the way of sending, infact must be GET and i have to use #ReuqestParam, i don't know how to send json data in postman parameters. I'm trying this and also other options but i always get error.
You can bind The request params to an object. In postman you will have 3 params ("agentName", "pageSize" and "pageNumber") and your controller will receive 2 objects
public ResponseEntity<ListResource> getList(#RequestParam("agentName") String agentName,
#Valid PaginationInfoList paginationInfo)
http://dolszewski.com/spring/how-to-bind-requestparam-to-object/
I'm trying to use the InMemoryClientExecutor to call services on my local JVM which return javax.ws.rs.core.Response objects. I can get this to work but only by specifying the String type like so:
String response = new ClientRequest("/myService", executor)
.get(String.class)
.getEntity();
Since the signature of the service is like so:
#GET
#Path("/myService")
public Response getSomeData(#Form MyFormBean bean) {
//...blah...
}
However I would like to get the actual Response objects back so that I can get the entities out and return those objects in my new "aggregate" response. When I just return the string the Jackson Parser doesn't see this as JSON, just a regular string so it does things like encoding line breaks into \n, etc.
Whenever I do something like:
String response = new ClientRequest("/myService",executor)
.get(Response.class)
.getEntity();
or even this to just get the plain request object:
String response = new ClientRequest("/myService", executor).get().getEntity();
I get the following Exception:
Exception Occured: org.jboss.resteasy.client.ClientResponseFailure: Unable to find a MessageBodyReader of content-type application/json and type null
at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:523)
at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:514)
at org.jboss.resteasy.client.core.BaseClientResponse.readFrom(BaseClientResponse.java:415)
at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:377)
at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:338)
Also present further down is:
Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.LoggableFailure: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:56)
at $Proxy210.getScheme(Unknown Source)
Where am I going wrong?
There is no Response object being returned from the server, just a data stream that, in your case, is the representation of some entity, in JSON format. Trying to deserialize this data back into a Response object on the client side will not work, because effectively you are saying the JSON represents a Response object, which it doesn't (it represents the entity that *used to be contained in the Response).
Good news is, there are other ways to obtain the entity, which do not require trying to back-spin it into a Response. You will need to have the entities on the classpath of your client:
MyEntity response = new ClientRequest("/myService", executor)
.get(MyEntity.class)
.getEntity();
Replace MyEntity with the type of the actual entity you are expecting to receive.
I have an action method defined like this in one of my controllers:
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody Post create(#Valid Post post, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// how to return an error status + error messages from here?
} else {
postRepository.persist(post);
return post;
}
}
When the post is persisted successfully, I return the post back to the client. But when it has validation errors, I want to return an Error status code as well as all the validation error messages back to the client.
What's the best way to do this?
Sine you are desigining a REST api, you need to create your own Pojo (aka. Resource) which will represent odd behaviour or validation errors, as stated by horaceman. I will show you how we do it in our application.
Since we are using JSON as a data representation, we wish to receive following information if unexpected exception occurs.
{ "status" : "EXCEPTION", "exceptionName" : "MyCustomException", "exceptionMsg" : "ex.unsupportedOperation" }
This is an example of course. Nice solution about it is that we can treat exceptionMsg as a key in our frontend to display proper i18n message or display it to the user as it is (in this case we use more descriptive messages).
Now, when everything is OK we do something like this:
{ "status" : "OK", "data" : {(...)} }
Data element is optional. We can send whatever we need to notify the frontend, or skip it totally.
The last scenario would be yours - validation errors. In this case we usually send following content:
{ "status" : "VALIDATION_FAILED", "errors" : [ "fieldName" : "username", "errorCode" : "validation.requiredField", "errorMsg" : "Username is required."] }
So clearly API clients will receive information that validation has failed and in proper fields - exact details about what went wrong. Of course errors is an array (or List), so we always provide as many details as necessary.
How I do it?
Easy, those objects are simple POJOS which are translated to JSON using Jackson. This gives me unlimited possibilities of JSON representation. What I do, is I'm preparing POJO representing Validation errors (for instance) and add it as a Model to my ModelAndView instance. Then I just rely on Spring to do proper JSON marshaling.
In your case you have #ResponseBody annotation with your Post instance, so as far as I know you won't be able to do that. Your setup is saying "Well, no matter what happens - always return an instance of Post". What you should do, is to replace it with simple ModelAndView, supply it with proper Model based on validation and return it to the client API.
For #ResponseBody I would remove BindigResult from the method signature and let the BindException be thrown. I would then use an #ExceptionHandler method to return an object that contains the errors as Likacz described.
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody Post create(#Valid Post post) {
postRepository.persist(post);
return post;
}
#ExceptionHandler
public ValidationErrors handleException(BindException ex) {
// ...
}
i think you want to make an ajax call in your controller. you return a post object in the method, so it is impossible to return another object(such as error message with code). how about return an ExecutionResult instead?
ExecutionResult{
private int statusCode;
private String message;
private Object yourPost;
//get and set methods here...
}
I am using cxf as a webservice.It supports xml and json format output of the requested data.I want to know that if some exception has occured in my code then i want to return him back the error code either in xml or json format.But i dont know when to give json and xml ,it depends on the requested url that user has asked.
example
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
PublisherReports getPublisherReportsAdView(
#PathParam("loginId") String loginId,
#QueryParam("fromDate") String fromDate,
#QueryParam("toDate") String toDate,
#QueryParam("filterValue") String filterValue);
If you mean you want to detect the mime type used to make the request, then you can use the #Consumes annotation to dictate which method handles which type of request. So you could write:
// Called when an XML request is made
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
#Consumes("application/xml")
PublisherReports getPublisherReportsAdViewXml(...
and:
// Called when a JSON request is made
#Path("/reports/ad-view/loginId/{loginId}/publisher/")
#Consumes("application/json")
PublisherReports getPublisherReportsAdViewJson(...
Then have each variant of the getPublisherReportsAdView() method call a common method to perform the actual processing logic but still handle exceptions differently depending on the method that gets called.
An alternative approach, which doesn't require additional methods, would be to add a parameter which is annotated with the #HeaderParam annotation and use that to hold the value of the 'Content-Type' request header.
e.g.:
PublisherReports getPublisherReportsAdView(
#PathParam("loginId") String loginId,
#QueryParam("fromDate") String fromDate,
#QueryParam("toDate") String toDate,
#QueryParam("filterValue") String filterValue,
#HeaderParam("Content-Type") String contentType)
{
...
The value of contentType will likely also include charset information, for example: application/json; charset=UTF-8 so you'll need to ignore that when working out if the request contained JSON or XML.