The task: Instead of receiving general HTTP 500 Internal Server Error
in my stacktrace and the same horrible stacktrace on the client side I want to see my customized message with another statuscode (403
for example), that it will be much clearer for the developer, what has happend. And add some message to User about the Exception.
Here are couple of changed classes from my application:
SERVER PART:
AppException.class
- all my Server Response exceptions (before giving back to client) I want to transform into this exception. Kinda standard entity class
public class AppException extends WebApplicationException {
Integer status;
/** application specific error code */
int code;
/** link documenting the exception */
String link;
/** detailed error description for developers */
String developerMessage;
public AppException(int status, int code, String message, String developerMessage, String link) {
super(message);
this.status = status;
this.code = code;
this.developerMessage = developerMessage;
this.link = link;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDeveloperMessage() {
return developerMessage;
}
public void setDeveloperMessage(String developerMessage) {
this.developerMessage = developerMessage;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public AppException() {
}
public AppException(String message) {
super("Something went wrong on the server");
}
}
ÀppExceptionMapper.class
- mapps my AppException to the JAX-RS Runtime, instead standard exception, client receives AppException.
@Provider
public class AppExceptionMapper implements ExceptionMapper<AppException> {
@Override
public Response toResponse(AppException exception) {
return Response.status(403)
.entity("toResponse entity").type("text/plain").build();
}
}
ApplicationService.class
- my Service class that throws AppException
@Path("/applications")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface ApplicationService {
@DELETE
@Path("/deleteById")
void deleteById(@NotNull Long id) throws AppException;
}
CLIENT PART:
ErrorHandlingFilter.class
- my Response catcher of the AppException. Here I want to transform each Response exception to another exception depending on the status.
@Provider
public class ErrorHandlingFilter implements ClientResponseFilter {
private static ObjectMapper _MAPPER = new ObjectMapper();
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
if (responseContext.getStatus() != Response.Status.OK.getStatusCode()) {
if(responseContext.hasEntity()) {
Error error = _MAPPER.readValue(responseContext.getEntityStream(), Error.class);
String message = error.getMessage();
Response.Status status = Response.Status.fromStatusCode(responseContext.getStatus());
AppException clientException;
switch (status) {
case INTERNAL_SERVER_ERROR:
clientException = new PermissionException(message);
break;
case NOT_FOUND:
clientException = new MyNotFoundException(message);
break;
default:
clientException = new WhatEverException(message);
}
throw clientException;
}
}
}
}
PermissionException.class
- exception in what I want to transform AppException, if it came with 500 status code.
public class PermissionException extends AppException{
public PermissionException(String message) {
super("403 - Forbidden. You dont have enough rights to delete this Application");
}
Integer status;
/** application specific error code */
int code;
/** link documenting the exception */
String link;
/** detailed error description for developers */
String developerMessage;
public PermissionException(int status, int code, String message, String developerMessage, String link) {
super(message);
this.status = status;
this.code = code;
this.developerMessage = developerMessage;
this.link = link;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDeveloperMessage() {
return developerMessage;
}
public void setDeveloperMessage(String developerMessage) {
this.developerMessage = developerMessage;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public PermissionException() {}
}
ApplicationPresenter.class
- piece of UI logic, where I want something to do with PermissionException thrown by the ErrorHandlingFilter.
@SpringPresenter
public class ApplicationPresenter implements ApplicationView.Observer {
@Resource
private ApplicationService applicationService;
@Resource
private UiEnvironment uiEnvironment;
@Override
public void deleteSelectedApplication(BeanItemGrid<Application> applicationGrid) {
try {
applicationService.deleteById(applicationGrid.getSelectedItem().getId());
} catch (PermissionException e) {
e.printStackTrace();
e.getMessage();
} catch (AppException e2) {
}
}
}
How can I resolve my problem? I am still receiving standard 500 InternalErrorException.
UPDATED ALMOST THE WHOLE QUESTION ONE MORE TIME!
When you have an ExceptionMapper, you don't catch the exception yourself, but have the framework catch it, when the resource method is invoked on an HTTP request.
The proper way to perform error handling is by registering ExceptionMapper
instances that know what response should be returned in case of specific (or generic) exception.
@Provider
public class PermissionExceptionHandler implements ExceptionMapper<PermissionException>{
@Override
public Response toResponse(PermissionException ex){
//You can place whatever logic you need here
return Response.status(403).entity(yourMessage).build();
}
}
Please take a look at my other answer for more details: https://stackoverflow.com/a/23858695/2588800
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With