I have the following code:
#POST
#Path("query")
#Produces(MediaType.APPLICATION_JSON)
public MyObject myMethod(#FormParam("id") String id)
{
//if some condition is met
if(...)
throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
else
//proceed to my logic and return myObject
}
So basically, if my web client, using AJAX, receives a Response.Status.SERVICE_UNAVAILABLE, it will show a customized web page. If the call is successful, it will show a different web page.
My questions is: Is there anyway that in myMethod, I can return the Response.Status.SERVICE_UNAVAILABLE without throwing the exception. Something like:
if(...)
return Response.Status.SERVICE_UNAVAILABLE)
else
//proceed my logic and return myObject
I basically want the client to know that its request cannot be fulfilled at this time and show a customized web page.
Your method should return a Response, instead of MyObject:
#POST
#Path("query")
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod(#FormParam("id") String id) {
if (/* error */) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
}
return Response.ok().entity(new MyObject(/* ... */)).build();
}
However, I would strongly recommend to use WebApplicationException for such situations, mostly for the sake of logical separation of regular and exceptional cases. This SERVICE_UNAVAILABLE response status (HTTP code 503) is a clear indicator of error, not a normal execution flow.
Related
I'm developing this Java RESTEASY application oriented to microservice pattern, i use methods like this to handle my exceptions:
#Path("/find/{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response retrieveItemById(#PathParam("id") String id) {
int id;
try {
itemDTO result = service.getItem(id);
return Response.ok(result).build();
}catch(Exception e) {
return Response.status(404).build();
}
}
Somebody told me that this method to handle exception (in this case item not found exception) is wrong, but I can't figure out why.
What is the right way to handle exception such as item not found, creation failed, updated failed ... in a REST oriented application?
Thanks.
I'm trying to write a Spring-WS client for a preexisting service. The endpoint offers two very similar actions, they both consume my data and respond with a simple object status; I need to use both. The difference is, one of them responds with HTTP status code 200 and the other with 202. In the first case the status object is decoded correctly and returned from WebServiceTemplate.marshallSendAndReceive(), but in the second case it's not decoded at all, and the method returns null.
According to the HTTP spec, the HTTP status 202 is Accepted, and its purpose is to indicate that the request has been received but not yet acted upon. However, the response may still contain useful information, like current request status or a completion estimate. I want to get this response.
I tried to debug the exact process and noticed my program executing the following code in the org.springframework.ws.transport.http.AbstractHttpSenderConnection.hasResponse() method:
protected final boolean hasResponse() throws IOException {
int responseCode = getResponseCode();
if (HttpTransportConstants.STATUS_ACCEPTED == responseCode ||
HttpTransportConstants.STATUS_NO_CONTENT == responseCode) {
return false;
}
...
}
This code fragment seems responsible for never getting the status object from the 202 Accepted response. (Or a 204 No Content response, but that's obviously acceptable.)
Is there a way around this? It doesn't seem possible to override this method in a bean, it's marked final.
The closest thing to an answer I could find was the following SWS JIRA ticket. It's marked "Resolved" since August 2012, but it's really not, as the comment from 2015 says.
my workaround:
Implement a custom HttpResponseInterceptor to handle a HTTP202:
public class MyInterceptor implements HttpResponseInterceptor {
#Override
public void process(HttpResponse httpResponse, HttpContext arg1) throws HttpException, IOException {
if (202 == httpResponse.getStatusLine().getStatusCode()) {
httpResponse.setStatusLine(new BasicStatusLine(httpResponse.getStatusLine().getProtocolVersion(),200,httpResponse.getStatusLine().getReasonPhrase()));
}
}
}
Now, add the interceptor to my http client builder when creating the webServiceTemplate
public CloseableHttpClient httpClient() throws Exception {
return HttpClientBuilder.create().addInterceptorLast(new MyInterceptor()).setSSLSocketFactory(sslConnectionSocketFactory()).build();
}
This question already has answers here:
How to handle REST Exceptions?
(2 answers)
Closed 7 years ago.
I would like to throw Exceptions from my REST endpoints. However, I am not too familiar with good REST design techniques. Consider the following...
//note the throws clause
#POST
public Response saveNewActivity(#HeaderParam("sessionTokenString") String sessionTokenString, Activity activity) throws Exception {
Activity result = as.saveNewActivity(activity);
if (result == null) {
throw new DuplicateDataException("blah blah blah");
}
return Response.ok(result).build();
}
versus handling Exceptions and explicitly returning only responses
#POST
public Response saveNewActivity(#HeaderParam("sessionTokenString") String sessionTokenString, Activity activity) {
try {
Activity result = as.saveNewActivity(activity);
if (result == null) {
throw new DuplicateDataException("blah blah blah");
}
return Response.ok(result).build();
} catch (Exception e) {
return Response.status(Response.Status.SOME_STATUS).build();
}
}
I can have the DuplicateDataException mapped using ExceptionMapper as follows
public class DuplicateDataExceptionMapper implements ExceptionMapper<DuplicateDataException> {
#Override
public Response toResponse(DuplicateDataException e) {
ErrorMessage errorMessage = new ErrorMessage ("Activity names must be unique.", <HttpStatusNumber>, "<add documentation here>");
return Response.status(Status.NOT_FOUND).entity(errorMessage).build();
}
}
Although in the end a Response gets returned anyways, but is one way of handling Exceptions (whether or not they are RuntimeExceptions) preferred over another, or does it not really matter? I have never seen a throws statement on a REST endpoint which is why I ask.
Please note that
this question or this question did not give the answer I am looking for.
If a parent class is catching the thrown exception and returning an appropriate HTTP Reponse error code (4xx), the initial code is fine.
If there's no parent class catching these to make them a 4xx instead of a 500, your code - to change the response code to something appropriate for this specific error - seems like a really good idea.
It is a bad idea to through an exception.
From the client perspective it results in an http 500 error code that don't tell nothing to an automatic program.
You should design your code trying to intercept all possible errors and reply with an appropriate error code inside your valid response. If your response in a json answer with something like the following:
{
statusCode: 345,
errorMessage: 'The error code message'
}
Leave the http status code 500 to unexpected errors.
I can make a GET with no problem at all.
When trying it with a POST request, I get this message:
Internal Server Error
The server encountered an unexpected condition which prevented it from fulfilling the request
I'm testing it with Simple REST Client extension for Chrome, but I get the same message in the real application.
This is my post:
#Post
public StringRepresentation pepe(Representation entity) {
StringRepresentation result = this.users();
// Parse the given representation and retrieve data
Form form = new Form(entity);
String action = form.getFirstValue("action");
if(action.equals("add")){
//nothing
}
Db.closeConnection();
return result;
}
And this is my #Get working properly:
#Get
public StringRepresentation pepe() {
String action = getQuery().getValues("action");
StringRepresentation result = null;
result = this.users();
Db.closeConnection();
return result;
}
And the funny thing is: whenever I remove the condition if(action.equals("add")){, (which was empty inside) the POST works correctly.
This would work:
#Post
public StringRepresentation pepe(Representation entity) {
StringRepresentation result = this.users();
// Parse the given representation and retrieve data
Form form = new Form(entity);
String action = form.getFirstValue("action");
Db.closeConnection();
return result;
}
What's going on? Looks so random!
Yes, your variable action will be null if you don't have an entry action within the form payload.
You can notice that Restlet provides a method getFirstValue with a default value parameter:
String action = form.getFirstValue("action", "defaultActionValue");
This could help you not to have NullPointerException.
Otherwise, it seems that you try to implement several actions for a method POST. I think that this blog post could give you some additional hints: https://templth.wordpress.com/2015/03/20/handling-multiple-actions-for-a-post-method/.
Hope it helps you,
Thierry
I am developing the RESTful webservices using Jersey & Spring 3.2 along with Open CMIS.
I am not using MVC pattern of Spring and it's just Spring IOC & Jersey SpringServlet, the controller class is something like below code
#GET
#Path("/{objId:.+}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public statusMsg addObject(#PathParam("objId") String objId{
return repoService.addObject(objId);
}
In the repoService I am performing the business logic to add the object using CMIS, my question is that I am catching around 5 exceptions related to CMIS then the base exception i.e Exception but for every service method I have to repeat it which I don't want to do.
I was searching on Google and found that #ControllerAdvice is the best solution for such problem wheer you can define all the checked & unchecked exceptions and wherever remove all the try catch blocks from the application. But it only work with MVC pattern.
Question 1: Is there a way I can use this in above Jersey-Spring framework?
After more reserach I found that Jersey provides ExceptionMapper to handle customized exception but I want to catch more CMIS exception or default Exception or IO Exception etc.
Question 2: How can I do it with ExceptionMapper?
Question 3: Am I on the correct approach or do you suggest any better approach to handle such issues.
Thanks in advance.
I use jersey2.11 with Tomcat and almost exception handle with ExceptionMapper.
(In domain logic, only DB rollback process use try-catch code.)
I think ExceptionMapper with #Provider automatically choose correct ExceptionMapper. So I suppose this function is satisfied with "I want to catch more CMIS exception or default Exception or IO Exception etc."
This code is my handling ExceptionMapper design code.
1.Some Jersey Root Resource Class
#GET
#Produces("application/json")
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception { // This level throws exceptions handled by ExceptionMapper
someComplexMethod(id, token); // possible throw Exception, IOException or other exceptions.
return CLICHED_MESSAGE;
}
2.ExceptionMapper package. com.yourdomain.exceptionmapper
AbstractExceptionMapper.java (All ExceptionMapper class extends this Abstract class)
public abstract class AbstractExceptionMapper {
private static Logger logger = LogManager.getLogger(); // Example log4j2.
protected Response errorResponse(int status, ResponseEntity responseEntity) {
return customizeResponse(status, responseEntity);
}
protected Response errorResponse(int status, ResponseEntity responseEntity, Throwable t) {
logger.catching(t); // logging stack trace.
return customizeResponse(status, responseEntity);
}
private Response customizeResponse(int status, ResponseEntity responseEntity) {
return Response.status(status).entity(responseEntity).build();
}
}
ExceptionMapper.java (At least this mapper can catch any exception which is not define specify exception mapper.)
#Provider
public class ExceptionMapper extends AbstractExceptionMapper implements
javax.ws.rs.ext.ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
// ResponseEntity class's Member Integer code, String message, Object data. For response format.
ResponseEntity re = new ResponseEntity(Code.ERROR_MISC);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
WebApplicationExceptionMapper.java (Specify WebApplicationException)
#Provider
public class WebApplicationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_WEB_APPLICATION);
return this.errorResponse(e.getResponse().getStatus(), re, e);
}
}
ConstraintViolationExceptionMapper.java (Specify Hibernate Validator ConstraintViolationException)
#Provider
public class ConstraintViolationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_CONSTRAINT_VIOLATION);
List<Map<String, ?>> data = new ArrayList<>();
Map<String, String> errorMap;
for (final ConstraintViolation<?> error : e.getConstraintViolations()) {
errorMap = new HashMap<>();
errorMap.put("attribute", error.getPropertyPath().toString());
errorMap.put("message", error.getMessage());
data.add(errorMap);
}
re.setData(data);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
.. and other specify exception can create ExceptionMapper classes.
In my experience, Exception Mapper is high level idea for focus to domain logic. It could drive out boring scattered try-catch block code from domain logic.
So I hope that you feel the "Yes i am" at Question 3 to resolve the problem at your environment.
you have not used try catch and throw anywhere across the application.
My code design use throws at method like this and this make to manage by ExceptionMapper classes.
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.
I think if simple project or never update/modify project (project lifecycle short time), your one class exception mapper approach ok.
But ... i never take this approach. Simply, if need to manage more exception, this method become big and complex, and hard to read and maintain becoming.
In my policy, OOP should use pleomorphism strategy any level code(class plan, DI plan) and this approach some part aim to drive out if/switch block in code. And this idea make each method short code and simple, clear to "domain logic" and code become to resistant to modify.
So i create implements ExceptionMapper and delegate to DI which ExceptionMapper class manage to exception.
(So DI manage replace your single class If block manage which exception handling, this is typically refactoring approach similar Extract xxx http://refactoring.com/catalog/extractClass.html.
In our discussion case, single class and one method too busy, so extract each ExceptionMapper class approaching and DI call suitable class & method strategy.)
Btw, system processing result is same at present point. But if need to reduce future development cost ,should not took approach one class exception handling plan. Because if give up simply code and refactor status, project code is dead faster.
This is my idea and why this.
regards.
thanks for your reply. I can see you have created multiple classes based on the exception type and behaviour.
Q1. In your services method are you throwing any exception like
public void addObject(String objId) throws WebApplicationException{
}
or you have not used try catch and throw anywhere across the application.
Actually, I have tried something where in my web application I am not using try, catch and throws anywhere and in my CentralControllerException I have mentioned like below:
public class CentralControllerHandler implements ExceptionMapper<Exception> {
#Override
#Produces(MediaType.APPLICATION_JSON)
public Response toResponse(Exception ex) {
if(ex instanceof CmisContentAlreadyExistsException){
log.error(ex);
// send Response status as 400
}
if(ex instanceof IOException){
log.error(ex);
// send Response status as 400
}
return Response;
}
}
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.