restygwt - get original server error on client site - java

I have an application build on GWT + RestyGWT with Spring
I'm trying to make some user friendly exception handling on client site.
I have some method on server side that throws an exception:
#PostMapping(...)
#Transactional(...)
public long withdraw(#PathVariable(value = "amount) long amount) throws CustomException {
if (amount < 0) {
throw new CustomException("Amount is negative");
}
account.withdraw(amount);
return account.balance;
}
It's called async from client side and handled there:
... new MethodCallback<...>() {
#Override
public void onFailure(Method method, Throwable throwable) {
// here should be error handling
}
How can I get original error message and class ("Amount is negative" and CustomException)? All I could get from method and throwable variables were:
errorCode = 500
response message = "Internal Server Error"
throwable is org.fusesource.restygwt.client.FailedResponseException

You cannot receive the same Exception in RestyGWT (this can be done using GWT RPC). But, you can handle exceptions uniformly in the server side (in jersey you can use an exception mapper in spring is called exception handler) and return an error response with a known JSON format. Then you can get this error response using the FailedResponseException (this is the exception you are receiving right now), this exception contains the response, so you can do MyKnownErrorResponse o = JSON.parse(failedResponseException.getResponse().getText()).

Related

How to throw exception based on feign.Response?

I have a Feign client with a method returning the feign.Response class. When another service throws an exception, feign puts an exception message on response body and puts status, but my service does not throw an exception. Can I throw an exception based on what I received in response like when I use ResponseEntity.
Feign client
#FeignClient(name = "ms-filestorage")
#RequestMapping(value = "/files", produces = "application/json")
public interface FileStorageApi {
#GetMapping(value = "/{id}")
Response getFileById(#PathVariable String id);
}
Usage of client
#Override
public Response getFileFromStorage(String fileId) {
Response fileStorageResponse = fileStorageApi.getFileById(fileId);
// NOW I USE THIS WAY FOR CHECKING RESPONSE BUT IT DOESN'T LOOK GOOD
//if (fileStorageResponse.status() != HttpStatus.OK.value()) {
// throw new OsagoServiceException();
//}
return fileStorageResponse;
}
Usually, if a Feign client call receives an error response from the API it is calling, it throws a FeignException.
This can be caught in a try / catch block (or a Feign ErrorDecoder if you want to be more sophisticated, but that's another post).
However, this is not the case if you map the error response into a Feign.Response return type - see this Github issue.
Instead of returning Feign.Response from getFileFromStorage(), you should create a custom Java object to hold the response, and you will then have access to the FeignException which you can handle as you wish.
Note that if you don't need access to the data that is returned from the API you are calling, changing the return type to void will also resolve this issue.

How to throw Custom Faults(faults not declared in wsdl) from Service Endpoint interface

I have SEI Class which throws an exception that is declared in WSDL file. During processing when this exception is thrown the SOAP Fault is sent to the client successfully. There is no problem here.
However, when we encounter any runtime exceptions in the server during processing we create a custom Fault and Throw the same from the SEI Class.
Since this Custom Fault is not declared in the SEI, we have added the Fault Class to extend RuntimeException. However, when this Custom Fault is thrown from the application code, the Websphere application server does not return the SOAP Fault to the Client. Instead it throws an exception and Http error code 500 is sent to the client.
Is there a way to send the Custom Fault message to the client without declaring the same in WSDL.
My WebMethod:
public CustomerDetails enquireCustomer(Customer customer)
throws CustomerFault
{
try
{
// SOME LOGIC HERE
}
catch (Exception exception)
{
if (exception instanceof CustomerFault)
throw ((CustomerFault) exception );
if (localException instanceof CustomerFault)
{
FaultDetails faultDetails = new FaultDetails();
faultDetails.setErrorId(1);
faultDetails.setErrorDescription(errorDescription);
throw new CustomerFault("Failed in Processing and other details here... ", faultDetails);
}
}
}
My Fault Class
import javax.xml.ws.WebFault;
#WebFault(name="CustomerFault", targetNamespace="http://www.mycompany.com")
public class CustomerFault extends RuntimeException
{
private static final long serialVersionUID = 1L;
private FaultDetails faultDetails;
public ServiceExecutionFault(String message, FaultDetails faultDetails) {
super(message);
this.faultDetails = faultDetails;
}
public ServiceExecutionFault(String message)
{
super(message);
}
public ServiceExecutionFault(String message, FaultDetails faultDetails,
Throwable cause) {
super(message, cause);
this.faultDetails = faultDetails;
}
public FaultDetails getFaultInfo() {
return faultDetails;
}
}
This issue seems to be there in Websphere alone. When tried in weblogic the same works fine without any issue. Is there any standard which I am missing here.
Found the answer here :
JAX-WS server-side SOAPHandler that returns fault gets "Internal Error" on WebSphere v8
By disabling the unified fault handling in websphere this worked fine.
Add the following JVM property.
-Dwebservices.unify.faults=false
This can be set from admin console :
Server -> Server Type -> Websphere Application Server -> Process
Definition -> Java Virtual Machine -> Custom Properties

Catch all Exceptions and also return custom Errors in Jersey

I want to catch all unexpected Exceptions in a jersey rest service.
Therefore i wrote an ExceptionMapper:
#Provider
public class ExceptionMapper implements javax.ws.rs.ext.ExceptionMapper<Exception> {
private static Logger logger = LogManager.getLogManager().getLogger(ExceptionMapper.class.getName());
#Override
public Response toResponse(Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Internal error").type("text/plain").build();
}
}
The mapper catches really all exceptions. Therefore i can't write:
public MyResult getById(#PathParam("id")) {
if (checkAnyThing) {
return new MyResult();
}
else {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
}
This is catched by the Mapper. Now i have to write:
public Response getById(#PathParam("id") {
if (checkAnyThing) { {
return Response.ok().entity(new MyResult()).build();
}
else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
Is this the correct way to catch all unexpected exceptions and also return errors (error codes) in jersey? Or is there any other (more correct) way?
WebApplicationException has a getResponse from which we can get the Response. So you can check for a WebApplicationException in your mapper. Maybe something like
#Override
public Response toResponse(Throwable error) {
Response response;
if (error instanceof WebApplicationException) {
WebApplicationException webEx = (WebApplicationException)error;
response = webEx.getResponse();
} else {
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Internal error").type("text/plain").build();
}
return response;
}
That way an instance of WebApplicationException thrown will just return the default response. This will actually handle some other exceptions also, not thrown explictly by your application. WebApplicationException has a few other exception under its hierarchy that are thrown by JAX-RS, for which predefined response/status codes are wrapped.
Exception Status code Description
-------------------------------------------------------------------------------
BadRequestException 400 Malformed message
NotAuthorizedException 401 Authentication failure
ForbiddenException 403 Not permitted to access
NotFoundException 404 Couldn’t find resource
NotAllowedException 405 HTTP method not supported
NotAcceptableException 406 Client media type requested
not supported
NotSupportedException 415 Client posted media type
not supported
InternalServerErrorException 500 General server error
ServiceUnavailableException 503 Server is temporarily unavailable
or busy
That being said, we could explicitly throw any of these exceptions in our code, just to give it more semantic value.
Generally speaking though, the example above may be unnecessary, unless you want to alter the response message/status code, as one can from the table above, the hierarchy of exceptions already have some general mapping. And in most cases, unexpected exceptions will already be mapped to InternalServerErrorException

Rest service throws exception : Best way to handle

I have a rest service which will throw an exception and I want to know what will be the best way to handle this.
So I have a rest service which can throw a userdefined exception and I am catching that inside the catch block and throwing that exception again ! and using rest framework to catch that. Similarly for non-user defined exceptions. I thought this will be good as I have number of rest services and all userdefinedexception code handling will be at a same place.
I would like to know is this the proper way of handling exception in rest service ?
I am using jersey.
// rest service
#POST
public void doSomething() {
try {
// ... some piece of code that can throw user defined exception as well as runtime exception
} catch(UserDefinedException e) {
throws new UserDefinedException(e);
} catch(Exception e) {
throws new ServiceException(e);
}
// Now I have a #Provider to catch this thrown exception
#Provider
public class UserDefinedExceptionHandler implements
ExceptionMapper {
public Response toResponse(UserDefinedException exception) {
ClientResponse clientResponse = new ClientResponse();
ResponseStatus status = new ResponseStatus();
clientResponse = handleUserDefinedException(exception, status, clientResponse);
return Response.ok(clientResponse).build();
}
// similarly for the ServiceException
Just raising error 500 at the server don't give much details on the error, one way to gracefully handle errors, is to wrap the response data in a structure with status and data, if the status is error, show the correct message.
something like this in json format :
{
"status": "error",
"data": {
"message": "detailed error message"
}
}
Handling exceptions in a REST service is not much different from handling exceptions in any other piece of code.
The only "convention" is to throw back an HTTP 400 if the exception is triggered by the client sending incorrect data and a 500 when your service is failing unexpectedly.

Handling Exception on Asynchronous Webservice Request

I am still new to implement web service request using Play!Framework 2.1 WS library. Now, I have problem on understanding the WS library behaviour.
Firstly, I have code like this :
public static Result espnRss() {
try {
// do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").get().map(
new F.Function<WS.Response, Result>() {
#Override
public Result apply(WS.Response response) throws Throwable {
return ok("Success!"); // success request
}
}
)
);
} catch (Exception e) {
// exception occured
return internalServerError("Oops, connect exception occured!");
}
}
When I try to request the espnRss action, I got SUCCESS response.
Then, I want to set WS timeout on the request. So, I changed my previous code like this :
public static Result espnRss() {
try {
// set request timeout for 1000 ms and do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").setTimeout(1000).get().map(
... // same as previous
)
);
} catch (Exception e) {
// exception occured
return internalServerError("Oops, connect exception occured!");
}
}
My internet connection is not fast (Download speed is about 40 KB/s) and I do that on purpose (set request time out for 1 second) to make exception handling code is executed.
But, I get default response from framework, not internalServerError response the code provided.
Execution Exception
[TimeoutException: No response received after 1000]
Can anyone explain me why the exception on WS request cannot be caught using my code above? How is the best way to handle exception using Play!Framework WS library?
To handle exception that occur on asynchronous request such as WS request with Play!Framework 2.1.0, there is method on Promise named recover(F.Function<java.lang.Throwable,A> function).
The method should be called when we want to handle all exception occured while requesting using WS library. So, I solved the problem using code that looked like following:
public static Result espnRss() {
// do request
return async(
WS.url("http://espnfc.com/rss/news?section=premierleague").setTimeout(100).get().map(
new F.Function<WS.Response, Result>() {
#Override
public Result apply(WS.Response response) throws Throwable {
return ok("Success!"); // success request
}
}
).recover( // to handle error occured on redeemed PROMISE
new F.Function<Throwable, Result>() {
#Override
public Result apply(Throwable throwable) throws Throwable {
// option to distinguish exception
if (throwable instanceof TimeoutException) {
return internalServerError("Oops, time out exception occured!");
} else {
return internalServerError("Oops, other exception occured!");
}
}
}
)
);
}
I am not familiar with the Play framework but async must be returning/using some kind of future. The request is actually performed in a separate Thread which Exceptions are obviously not caught by your try..catch handler.
There must be some function/method like onComplete that you can apply to async allowing you to test the result of running the request.

Categories

Resources