I read about custom exception and as:
Thorben suggest here:
https://stackify.com/java-custom-exceptions/#wpautbox_about
Baeldung suggested here: https://www.baeldung.com/java-new-custom-exception
A custom exception should be more beneficial than the original exception, otherwise it would loose its purpose.Right?
To do that we should always pass the throwable cause to our custom exception.
I have my application specific ErrorCode enums which have a custom error code and a custom message.
#Getter
#AllArgsConstructor
public enum ErrorType {
DATABASE_SERVICE_UNAVAILABLE(9001, "Cant persist to Database"),
//and more...
private final int errorCode;
private final String errorMessage;
}
While writing a exception mapper what should I send as response?
1)Custom ErrorCode Enum (Only errorcode and error msg)
OR
2)Custom ErrorCode Enum + Throwable cause (Both)
If we not send throwable, then what would be its purpose?
While writing a exception mapper what should I send as response?
If by "response", you mean the response returned by a Controller, then I think you should send the error code and error message. Why would a client be interested in your throwable object. Just give the client an understandable reason for the error. You should just log the exception in your application for debugging purpose.
Related
I've got two root exception types my service is throwing
class ServiceException extends RuntimeException {
private Status status;
private String someString;
// Boilerplate omitted
}
class RetryableServiceException extends ServiceException {
// This class has no new fields
}
Because there's a common retry framework our clients will use which determines whether to retry or not based on the exception class.
But the problem, obviously, is that when the client gets the response and calls Response.readEntity(Class <T> entityType) they will just get an instance of whatever class they're trying to read, since they have the same fields.
Clearly I need to add some other field which distinguishes these two objects, but how can I add that to the builders and constructors in a way that:
Doesn't require a ton of client logic,
doesn't needlessly complicate the exception objects, and
can be understood by Jackson?
To answer your main issue, You don't want to couple the clients and the server so tightly by having the clients use the same exact Exception classes used on the server, create a generic error bean and map exceptions to that bean then serialise/de-serialise it. You can do that in a transparent way using javax.ws.rs.ext.ExceptionMapper, this error bean can have canRetry or shouldRetry fields. An example implementation
public class RetryableServiceExceptionMapper implements ExceptionMapper<RetryableServiceException> {
#Context
Request request;
public Response toResponse(RetryableServiceException exception) {
ApiError error = ApiError.builder().canRetry(true).message(exception.getMessage()).build();
return Response.status(status).cacheControl(cacheControl).tag(eTag).entity(error).type(APPLICATION_XML);;
}
}
Suppose I've got an endpoint in Dropwizard, say
#GET
public Response foo() { throw new NullPointerException(); }
When I hit this endpoint it logs the exception and everything, which is great! I love it. What I love less is that it returns a big status object to the user with status: ERROR (which is fine) as well as a gigantic stack trace, which I'm less excited about.
Obviously it's best to catch and deal with exceptions on my own, but from time to time they're going to slip through. Writing a try catch block around the entire resource every time is fine, but (a) it's cumbersome, and (b) I always prefer automated solutions to "you have to remember" solutions.
So what I would like is something that does the following:
Logs the stack trace (I use slf4j but I assume it would work for whatever)
Returns a general purpose error response, which does not expose potentially privileged information about my server!
I feel like there must be a built-in way to do this -- it already handles exceptions in a relatively nice way -- but searching the docs hasn't turned up anything. Is there a good solution for this?
As alluded to by reek in the comments, the answer is an ExceptionMapper. You'll need a class like this:
#Provider
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
#Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
You can do whatever logging or etc. you like in the toResponse method, and the return value is what is actually sent up to the requester. This way you have complete control, and should set up sane defaults -- remember this is for errors that slip through, not for errors you actually expect to see! This is also a good time to set up different behaviors depending on what kind of exceptions you're getting.
To actually make this do anything, simply insert the following line (or similar) in the run method of your main dropwizard application:
environment.jersey().register(new RuntimeExceptionMapper());
where environment is the Environment parameter to the Application's run method. Now when you have an uncaught RuntimeException somewhere, this will trigger, rather than whatever dropwizard was doing before.
NB: this is still not an excuse not to catch and deal with your exceptions carefully!
Add the following to your yaml file. Note that it will remove all the default exception mappers that dropwizard adds.
server:
registerDefaultExceptionMappers: false
Write a custom exception mapper as below:
public class CustomExceptionMapper implements ExceptionMapper<RuntimeException> {
#Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
Then register the exception mapper in jersey:
environment.jersey().register(new CustomExceptionMapper());
Already mentioned this under the comments, but then thought I would give it a try with a use case.
Would suggest you to start differentiating the Exception that you would be throwing. Use custom exception for the failures you know and throw those with pretty logging. At the same RuntimeException should actually be fixed. Anyhow if you don't want to display stack trace to the end user you can probably catch a generic exception, log the details and customize the Response and entity accordingly.
You can define a
public class ErrorResponse {
private int code;
private String message;
public ErrorResponse() {
}
public ErrorResponse(int code, String message) {
this.code = code;
this.message = message;
}
... setters and getters
}
and then within you resource code you can modify the method as -
#GET
public Response foo() {
try {
...
return Response.status(HttpStatus.SC_OK).entity(response).build();
} catch (CustomBadRequestException ce) {
log.error(ce.printStackTrace());
return Response.status(HttpStatus.SC_BAD_REQUEST).entity(new ErrorResponse(HttpStatus.SC_BAD_REQUEST, ce.getMessage())).build();
} catch (Exception e) {
log.error(e.printStackTrace(e));
return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage())).build();
}
}
This article details Checked and Unchecked Exceptions implementation for Jersey with customized ExceptionMapper:
https://www.codepedia.org/ama/error-handling-in-rest-api-with-jersey/
Official Dropwizard documentation also covers a simpler approach, just catching using WebApplicationException:
#GET
#Path("/{collection}")
public Saying reduceCols(#PathParam("collection") String collection) {
if (!collectionMap.containsKey(collection)) {
final String msg = String.format("Collection %s does not exist", collection);
throw new WebApplicationException(msg, Status.NOT_FOUND)
}
// ...
}
https://www.dropwizard.io/en/stable/manual/core.html#responses
It worked for me by simply registering the custom exception mapper created in the run method of the main class.
environment.jersey().register(new CustomExceptionMapper());
where CustomExceptionMapper can implement ExceptionMapper class like this
public class CustomExceptionMapperimplements ExceptionMapper<Exception>
I recently came across norm of a SystemWide Exception class with enum for failure types
Class SystemWideException extends RuntimeException{
ErrorCause cause; //enum
ErrorCode code; //enum
Module where; //enum
Map<key,value> properties map
...
Here is how it is thrown
throw new SystemException(ThisModule.moduleX,ErrorCause.causeY,Errorcode.codeZ)
.set("field", field)
.set("value", value)
.set("min-length", MIN_LENGTH);
}
A system wide exception can be useful like the one mentioned here but i doubt if there is any use to have the component where exception occured and why it occured in the exception object?
I have a restful web service where i use a ExceptionMapper.I can use central logging here and the stacktrace gives why and where.Information about response status and body come from the exception object
Is there any use case where it would be meaningful to have Component,What,Why in the exception object?
Update: one use i have seen is multilingual support of error messages where Component+Error code form the key
This question already has answers here:
Should web services throw exceptions OR result objects
(7 answers)
Closed 8 years ago.
I want define service as web service.
I define a method with register name. Its a class as input parameter with RegisterParam name and a return type with RegisterResult name as output.
public class RegisterParam{
String name;
String family;
}
public class RegisterResult{
Integer registr_id;
}
public interface Service{
public RegisterResult register(RegistrParam param);
}
If register service failed and its logic not doing so I have two solution for notify to service caller:
In RegisterResult class add a property as result_code and a enumeration for its value. If its value is zero means register sercice successfully done and if its value is else of zero means register service failed and result_code shows reason of fail.
register service throws a exception when it is falied and if dont any exception throwed means register service done successfully.
My question is: what above solution is bettr and why?
I think you should differ two different scenarios:
1) An exception occurs, like some environment (e.g. database) is not available.
In this case I would throw an exception which is automatically converted into an SOAPFault by the web service implementation. The advantage on this one is, that the caller of your service get's also an exception and can handle that by it's exception handling.
2) An expected business "error" happend, like the user is not logged in or did not provide the necessary information to enable the service to complete successful.
The caller of your web service receives an response message which the caller has to interpret and maybe wants to show it to the user which provided the information.
At the end it depends on your interface contract you provide to your interface users! Most important on that one is to describe how your service handles different errors scenarios.
case 1 no result:
public interface Service{
public void register(RegistrParam param);
}
In this case your Service can send a HTTP Status Code like 200. Your client will interpret the status code this way:
200: ok i'm registered
400: hm don't know why but failed...
If you want to understand what happened and why is your request failed with 400 error, you have to check your server logs or something like that.
case 2 with result:
public interface Service{
public Response register(RegistrParam param);
}
I'm sending always a Response object to my clients:
public class Response {
private ResponseStatus status; // enum: (OK, ERROR, BAD_REQUEST)
private ResultType type; // enum: (RegisterResult, LoginResult etc...) defines how to interpret the field "data"
private Object data; // RegisterResult.java as jsonstring or Exception.java as jsonstring etc...
private long time = -1L; // execution time
}
If I'm developing my client, I can always understand why my request was failed.
I'm writting a client-server application. Now I'm just doing error handling. If a error occurs at the server (after a request from the client), the server should create an error object, serialize it and send it to the client.
In the error object I have a field for the error code. Of course I could place an enum in this object listing all possible error I want to cover, but then the serialized object gets to big.
Thus, I'm thinking about writting an external enum class available for the server and the client and only sending the error code from the server to the client.
Would this be a good idea?
If the client receives such an error code how can he then look up the corresponding enum in the enum class?
Just send the error code that you defined in your enum:
public enum ErrorCode {
OK(0), KO(1);
// ...
}
public class Error implements Serializable {
private int code;
private String message;
// ...
}
public void myMethod() {
// ...
// something went bad!
InternalError ie = getMyInternalErrorSomehow();
Error error = new Error(ie.getErrorCode().getCode(),
"something bad happened and i am sending you a nice message");
client.send(error);
}