Jersey... how to log all exceptions, but still invoke ExceptionMappers - java

I'm in a little bit of bind... want my cake and to eat it too.
I want to log all exceptions my application throws. So if someone hits an incorrect URL, i want to log the stack trace to SLF4J.
So you're probably thinking, 'hey thats easy, just implement an exceptionmapper and log the exception." So I did:
public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> {
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
/**
* {#inheritDoc}
*/
#Override
public Response toResponse(Exception exception) {
log.error("toResponse() caught exception", exception);
return null;
}
}
If you do this, instead of 404 errors when someone types a wrong URL in, they get a 500 error. One would guess returning null would propagate the exception down the chain handlers, but Jersey doesn't do that. It actually provides very little info why it would choose one handler over another...
Has anyone ran into this problem and how did you solve it?

You can use a RequestEventListener to listen for an exception event and log the throwable, without interfering with any existing processing. Note that this means first registering an ApplicationEventListener which then returns an instance of RequestEventListener. The following does both implemented in a single class:
#Provider
public class ExceptionLogger implements ApplicationEventListener, RequestEventListener {
private static final Logger log = LoggerFactory.getLogger(RequestExceptionLogger.class);
#Override
public void onEvent(final ApplicationEvent applicationEvent) {
}
#Override
public RequestEventListener onRequest(final RequestEvent requestEvent) {
return this;
}
#Override
public void onEvent(RequestEvent paramRequestEvent) {
if(paramRequestEvent.getType() == Type.ON_EXCEPTION) {
log.error("", paramRequestEvent.getException());
}
}
}

To return the correct http status code, your exception mapper could look something like this:
#Provider
public class RestExceptionMapper implements ExceptionMapper<Throwable>
{
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
#Override
public Response toResponse(Throwable exception)
{
log.error("toResponse() caught exception", exception);
return Response.status(getStatusCode(exception))
.entity(getEntity(exception))
.build();
}
/*
* Get appropriate HTTP status code for an exception.
*/
private int getStatusCode(Throwable exception)
{
if (exception instanceof WebApplicationException)
{
return ((WebApplicationException)exception).getResponse().getStatus();
}
return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
}
/*
* Get response body for an exception.
*/
private Object getEntity(Throwable exception)
{
// return stack trace for debugging (probably don't want this in prod...)
StringWriter errorMsg = new StringWriter();
exception.printStackTrace(new PrintWriter(errorMsg));
return errorMsg.toString();
}
}
Also it sounds like you are interested in cascading exception mappers, but according to the spec this isn't possible:
JAX-RS 2.0 Spec, Chapter 4.4
"Exception mapping providers map a checked or runtime exception to an instance of Response. An exception
mapping provider implements the ExceptionMapper interface and may be annotated with
#Provider for automatic discovery. When choosing an exception mapping provider to map an exception,
an implementation MUST use the provider whose generic type is the nearest superclass of the exception.
When a resource class or provider method throws an exception for which there is an exception mapping
provider, the matching provider is used to obtain a Response instance. The resulting Response is processed
as if a web resource method had returned the Response, see Section 3.3.3. In particular, a mapped
Response MUST be processed using the ContainerResponse filter chain defined in Chapter 6.
To avoid a potentially infinite loop, a single exception mapper must be used during the processing of a
request and its corresponding response. JAX-RS implementations MUST NOT attempt to map exceptions
thrown while processing a response previously mapped from an exception. Instead, this exception MUST
be processed as described in steps 3 and 4 in Section 3.3.4."

Related

Spring Webflux - Proper way to throw checked custom exception (not RuntimeException)

May I ask what is the proper way to throw checked custom exception in Spring webflux please?
I would like to insist, it is about checked custom exception, like MyException.java, not something like RuntimeException, and it is about throwing exception, not handling exception.
I tried the following :
#Controller
#SpringBootApplication
public class QuestionHowToThrowException {
public static void main(String[] args) {
SpringApplication.run(QuestionHowToThrowException.class);
}
#PostMapping(path = "/question", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity<QuestionResponse>> question(#RequestBody QuestionRequest questionRequest) {
Mono<FirstStep> firstStepMono = WebClient.create().post().uri("http://firstWebService:8111/getFirstStep")
.body(questionRequest.getThing(), String.class).retrieve().bodyToMono(FirstStep.class);
Mono<SecondStep> secondStepMono = firstStepMono.map(oneFirstStep -> getSecondStepFromFirstStepAfterCheck(oneFirstStep));
return secondStepMono.map(oneSecondStep -> ResponseEntity.ok(new QuestionResponse(oneSecondStep.getSecondThing())));
}
private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException {
if (firstStep.getThingNeedsToCheckCanThrowException().equals("exception")) {
throw new MyException("exception");
} else {
return new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good");
}
}
public class QuestionRequest {
private String thing;
public String getThing() {
return thing;
}
}
public class QuestionResponse {
private String response;
public QuestionResponse(String response) {
this.response = response;
}
}
public class FirstStep {
private String thingNeedsToCheckCanThrowException;
public String getThingNeedsToCheckCanThrowException() {
return thingNeedsToCheckCanThrowException;
}
}
public class SecondStep {
private String secondThing;
public SecondStep(String secondThing) {
this.secondThing = secondThing;
}
public String getSecondThing() {
return secondThing;
}
}
}
This is not possible, since there in an unhandled exception in getSecondStepFromFirstStepAfterCheck method.
If I throw and propagate, private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException the lambda caller method is not happy.
What is the cleanest and proper way to throw custom exception in webflux please?
Thank you
Reading through your sample code, it looks like you are trying to introduce some error handling with on your Mono.
You can create an unchecked exception by extending the RuntimeException class. If you want a checked exception that enforces handling, you can simply extend Exception.
public class MyException extends RuntimeException {
public MyException(String msg) {
super(s);
}
}
The cleanest way to throw an exception with the Reactor project is really just to throw it. There are error handling functions that allow you to provide different flows to certain error cases.
The good news is you have several options that provides some flow control for error handling.
Project Reactor provides several of these methods on the Mono object.
doOnError(),onErrorContinue(),onErrorReturn(),onErrorStop(),onErrorMap()
I am not entirely sure what you are trying to achieve with the following sample code.
return Mono.error(new MyException("exception"));
} else {
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good"));
But this looks like a good case for a onErrorMap() since it looks like you are trying to translate some exception here
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good")
.onErrorMap(e -> "translated result");
For our applications, we have our custom base exception extend from RuntimeException. We then have standard exception handling that looks for our custom exception for special handling before returning results back to the end user. This allows us to use normal throws mechanics since we want all exceptions thrown to ripple up the top level of the call.
For performance concerns webflux and reactive are slightly lower performance on a per call basis especially for calls that don't need to do any parallelization. However once load is put onto the system it tends to become more performant primarily related to garbage collection. Overhead from the difference between map and flatMap should be negligible at best.

How to create a custom error/exception handler for graphql?

So, I have been coding a microservice which uses GraphQL's java implementation for APIs. GraphQL enforces some level of validation for the supplied queries by client. However, in cases when the issue occurs inside resolving the query, I have seen graphql show messages which exposes the internals of the micr-service.
What do I need? A way to handle all exceptions/errors thrown from resolver functions in such a way that I can sanitize the exceptions/errors before GraphQL creates corresponding response.
I have looked up official documentation and many stack over flow questions, but failed to find any place it talks about handling. If I found any, they were for previous versions and are no more supported.
Some of the links I referred -
1. https://www.howtographql.com/graphql-java/7-error-handling/
2. GraphQL java send custom error in json format
3. https://www.graphql-java.com/documentation/v13/execution/
I have already done the below things like -
Creating custom handler
#Bean
public GraphQLErrorHandler errorHandler() {
return new CustomGraphQLErrorHandler();
}
public class CustomGraphQLErrorHandler implements GraphQLErrorHandler {
#Override
public List<GraphQLError> processErrors(List<GraphQLError> errors) {
List<GraphQLError> clientErrors = errors.stream()
.filter(this::isClientError)
.collect(Collectors.toList());
List<GraphQLError> serverErrors = errors.stream()
.filter(this::isSystemError)
.map(GraphQLErrorAdapter::new)
.collect(Collectors.toList());
List<GraphQLError> e = new ArrayList<>();
e.addAll(clientErrors);
e.addAll(serverErrors);
return e;
}
private boolean isSystemError(GraphQLError error) {
return !isClientError(error);
}
private boolean isClientError(GraphQLError error) {
return !(error instanceof ExceptionWhileDataFetching || error instanceof Throwable);
}
}```
Expected behavior - The control would reach to `processErrors` method. Actual - It doesn't reach there.
You need to override the errorsPresent method in GraphQLErrorHandler to return true when an error is passed into that method. Something like:
#Override
public boolean errorsPresent(List<GraphQLError> errors) {
return !CollectionUtils.isEmpty(errors);
}

RestTemplate & ResponseErrorHandler: Elegant means of handling errors given an indeterminate return object

Using a RestTemplate, I am querying a remote API to return an object either of expected type (if HTTP 2xx) or an APIError (if HTTP 4xx / 5xx).
Because the response object is indeterminate, I have implemented a custom ResponseErrorHandler and overridden handleError(ClientHttpResponse clientHttpResponse) in order to extract the APIError when it occurs. So far so good:
#Component
public class RemoteAPI {
public UserOrders getUserOrders(User user) {
addAuthorizationHeader(httpHeaders, user.getAccessToken());
HttpEntity<TokenRequest> request = new HttpEntity<>(HEADERS);
return restTemplate.postForObject(CUSTOMER_ORDERS_URI, request, UserOrders.class);
}
private class APIResponseErrorHandler implements ResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) {
try {
APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);
} catch ...
}
}
private void refreshAccessToken(User user) {
addAuthorizationHeader(httpHeaders, user.getAccessSecret());
HttpEntity<TokenRequest> request = new HttpEntity<>(HEADERS);
user.setAccessToken(restTemplate.postForObject(TOKEN_REFRESH_URI, request, AccessToken.class));
}
}
The challenge is that getUserOrders(), or a similar API call, will occasionally fail with a 'recoverable' error; for instance, the API access token may have expired. We should then make an API call to refreshAccessToken() before re-attempting getUserOrders(). Recoverable errors such as these should be hidden from the user until the same ones have occurred multiple times, at which point they are are deemed non-recoverable / critical.
Any errors which are 'critical' (e.g.: second failures, complete authentication failure, or transport layer failures) should be reported to the user as there is no automatic recovery available.
What is the most elegant and robust way managing the error handling logic, bearing in mind that the type of object being returned is not known until runtime?
Option 1: Error object as a class variable with try / catch in each API call method:
#Component
public class RemoteAPI {
private APIError apiError;
private class APIResponseErrorHandler implements ResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) {
try {
this.apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);
} catch ...
}
}
public UserOrders getUserOrders(User user) {
try {
userOrders = restTemplate.postForObject(CUSTOMER_ORDERS_URI, request, UserOrders.class);
} catch (RestClientException ex) {
// Check this.apiError for type of error
// Check how many times this API call has been attempted; compare against maximum
// Try again, or report back as a failure
}
return userOrders;
}
}
Pros: Clarity on which method originally made the call
Cons: Use of a class variable for a transient value. Lots of boilerplate code for each method that calls the API. Error handling logic spread around multiple methods.
Option 2: User object as a class variable / Error management logic in the ResponseErrorHandler
#Component
public class RemoteAPI {
private User user;
private class APIResponseErrorHandler implements ResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) {
try {
APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);
// Check this.apiError for type of error
// Check how many times this API call has been attempted; compare against maximum
// Try again...
getUserOrders();
...or report back as a failure
} catch ...
}
}
Pros: Error management logic is in one place.
Cons: User object must now be a class variable and handled gracefully, because the User object cannot otherwise be accessible within the ResponseErrorHandler and so cannot pass it to getUserOrders(User) as before. Need to keep track of how many times each method has been called.
Option 3: Error management logic outside of the RemoteAPI class
Pros: Separates error handling from business logic
Cons: API logic is now in another class
Thank you for any advice.
Answering my own question: it turns out that there were fallacies in the question itself.
I was implementing a ResponseErrorHandler because I thought I needed it to parse the response even when that response was returned with a HTTP error code. In fact, that isn't the case.
This answer demonstrates that the response can be parsed into an object by catching a HttpStatusCodeException and otherwise using a standard RestTemplate. That negates the need for a custom ResponseErrorHandler and therefore the need to return an object of ambiguous type. The method that is handed the error can catch the HttpStatusCodeException, try to refresh the access token, and then call itself again via recursion. A counter is required to prevent endless recursion but that can be passed through rather than being a class variable.
The downside is that it still requires error management logic spread around the class, along with plenty of boilerplate code, but it's a lot tidier than the other options.
public UserOrders getUserOrders(User user, Integer methodCallCount) {
methodCallCount++;
UserOrders userOrders;
try {
userOrders = restTemplate.postForObject(USER_ORDERS_URI, request, UserOrders.class);
} catch (RestClientException ex) {
APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);
if (methodCallCount < MAX_METHOD_CALLS) {
if (apiError.isType(ACCESS_TOKEN_EXPIRED)) {
refreshVendorAccessTokenInfo(user);
userOrders = getUserOrders(user, methodCallCount);
}
}
}
return userOrders;
}

Receive custom exceptions from Restlet Framework in GWT client

I want to use Exception handling with the Restlet Framework and GWT clients.
The Restlet Framework supports the concept of annotated exceptions as described in this post;
http://restlet.com/company/blog/2015/12/21/exception-handling-with-restlet-framework/
In my project i created a LocationNameException
#Status(value = 409)
public class LocationNameException extends Exception
{
...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public LocationNameException(String pMessage, Throwable pCause)
{
super(pMessage, pCause);
}
}
And use this in my ServerResource;
#Override
#Transactional(rollbackOn = LocationNameException.class)
public LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException
{
...
Location lLocation = new Location(pLocationDto);
try
{
LocationDao lLocationDao = getLocationDao();
lLocationDao.persist(lLocation);
}
catch (PersistenceException pPersistenceException)
{
throw new LocationNameException("Location requires unique Name", pPersistenceException);
}
...
return lLocationDto;
}
With the interface
public interface LocationListServerResourceInt
{
...
#Post
LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException;
...
}
This works, in the case of an exception the call returns code 409;
And at the GWT client side onFailure() is called;
private class PostLocationCallback implements AsyncCallback<LocationDto>
{
...
#Override
public void onFailure(Throwable pCaught)
{
mCallback.onFailure(pCaught, mLocationDto);
}
}
But parameter pCaught only contains a ResourceException with the status code 409.
My LocationNameException isn't included in the underlying cause stack.
I need this LocationNameException for appropriate error message handling.
The reason is the generated ServerResourceProxy LocationListServerResourceProxyImpl by the Restlet GWT ClientProxyGenerator;
public void postLocation(LocationDto param1, final LocationDto> callback)
{
...
public void handle(Request request, Response response)
{
if (getClientResource().getStatus().isError())
{
callback.onFailure(new ResourceException(getClientResource().getStatus()));
}
else
{
...
}
I think i have to rewrite the Post method in the ClientProxyGenerator;
The LocationNameException is present in the Response data so the Basic approach using the getResponseEntity() method of the ClientResource class should be possible.
Is this the way to go? Or can i catch the LocationNameException exception somewhere else as suggested by Catching annotated exceptions?
It is really hard to try a different approach because of the generated code. Is there an easy way to circumvent the code generator with custom classes?
As already mentioned the LocationNameException is present in the Response data.
Therefore we can get it, just like a normal entity;
...
public void handle(Request request, Response response)
{
if (getClientResource().getStatus().isError())
{
LocationNameException lLocationNameException = null;
boolean serializationError = false;
try
{
if (response.isEntityAvailable())
{
if (MediaType.APPLICATION_JAVA_OBJECT_GWT.equals(response.getEntity().getMediaType()))
{
lLocationNameException = new ObjectRepresentation<LocationNameException>(
response.getEntity().getText(),
(SerializationStreamFactory) MyLocationListServerResourceProxyImpl.this, false)
.getObject();
}
else
{
throw new IOException("Can't parse the enclosed LocationNameException.");
}
}
}
catch (Throwable e)
{
serializationError = true;
callback.onFailure(new ResourceException(e));
}
if (!serializationError)
{
callback.onFailure(lLocationNameException);
}
}
else
{
...
The ClientProxyGenerator needs to know the exception type (in this case LocationNameException). Therefore we specify the exception in the ClientProxy interface;
#Post
void postLocation(LocationDto pLocationDto, AsyncCallback<LocationDto> pResult) throws LocationNameException;
And use getExceptionTypes() or getGenericExceptionTypes() in the ClientProxyGenerator;
Class<?>[] exceptionTypes = method.getExceptionTypes();
java.lang.reflect.Type[] genericExceptionTypes = method.getGenericExceptionTypes();
Of course not all REST methods use a custom exception. When getExceptionTypes() returns an empty list we just return the good old status code;
callback.onFailure(new ResourceException(getClientResource().getStatus()));
With help of Jerome Louvel and Thierry Boileau i created a new ClientProxyGenerator() that supports custom exceptions towards a GWT client;
Just specify the exception from the interface in the ServerResourceProxy (ClientProxy)
and voilĂ 
It is possible to use this custom ClientProxyGenerator() in your project right away.
Download custom ClientProxyGenerator
And place it in a package on the server (for example package com.ludus.server.util)
In GWT module XML change the ClientProxyGenerator to the new version on the server;
And you're ready to go with your custom exceptions, but it would be nice if this extension would be integrated in the Restlet framework.

Global Exception Handling in Jersey & Spring?

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.

Categories