How to create global exception handler - actframework

In actframework, we can use #catch to handle exception, but it's only working in current class and parent class. What can i do if i want to create a global exception handler, just like #ExceptionHandler in SpringBoot?

Just add #Global annotation to your #Catch method, e.g.
public class AppExceptionHandler {
#Global
#Catch(value = Throwable.class, priority = 1)
public void logThrowable(Throwable throwable) {
AppEntry.LOGGER.error(throwable, "Global Exception Handler: %s", throwable.getMessage());
}
}
With the given code above, it will catch exception triggered in any request handler, e.g,

You can use #ControllerAdvice to create Global Exception Handler in spring boot. Below answer has sample code snippet that explains the same.
#ControllerAdvice even by setting the highest precedense for RestControllers not working as it should

Related

Exception handling in parent router

I have parent router that calls other routers. The parent router has all the exception handling logic. In all child routers, on exception, I want to just add properties in the exchange object and leave the actual exception handling in the parent(main) router.
Example:
public class ParentRouter extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(CustomException.class)
.process(new ExceptionProcessor())
.handled(true);
from("direct:parent-route").to("direct:child-route");
from("direct:child-route")
.onException(CustomException.class)
.process(new Processor(){
#Override
public process(Exchange exchange){
exchange.setProperty("childExceptionFlg", "true");
}
});
}
As per my requirement, when CustomExpection is thrown in the child router, it should add a property to the exchange object and the final handling code needs to be executed in the ExceptionProcessor in the parent router.
What you try to achieve can be done using routes dedicated to error handling that call each other (child error handler route calls parent error handler route) or at least a route for the main error handler that is called by the exception policy of your child routes.
Something like:
// The main logic of the main exception policy is moved to a dedicated
// route called direct:main-error-handler
onException(CustomException.class)
.to("direct:main-error-handler")
.handled(true);
from("direct:parent-route").to("direct:child-route");
from("direct:child-route")
.onException(CustomException.class)
// Set the exchange property childExceptionFlg to true
.setProperty("childExceptionFlg", constant("true"))
// Call explicitly the main logic of the the main exception policy once
// the property is set
.to("direct:main-error-handler")
// Flag the exception as handled
.handled(true)
.end()
// Throw a custom exception to simulate your use case
.throwException(new CustomException());
from("direct:main-error-handler")
.log("Property childExceptionFlg set to ${exchangeProperty.childExceptionFlg}");
Result:
INFO route3 - Property childExceptionFlg set to true

When to use ResponseStatusException and ControllerAdvice

Spring5 has introduced ResponseStatusException, which has put me in a dilemma as to in what scenario I can use a ResponseStatusException and ControllerAdvice as both of them are quiet similar.
Can anyone help me with this.
Thanks in advance.
Lets first understand what is ResponseStatusException and ControllerAdvice
ResponseStatusException is a programmatic alternative to #ResponseStatus and is the base class for exceptions used for applying a status code to an HTTP response.
#GetMapping("/actor/{id}")
public String getActorName(#PathVariable("id") int id) {
try {
return actorService.getActor(id);
} catch (ActorNotFoundException ex) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Actor Not Found", ex);
}
}
The #ControllerAdvice annotation allows us to consolidate multiple, scattered #ExceptionHandlers into a single, global error handling component.
#ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
#ExceptionHandler(value
= { IllegalArgumentException.class, IllegalStateException.class })
protected ResponseEntity<Object> handleConflict(
RuntimeException ex, WebRequest request) {
return ResponseEntity<Object>;
}
}
Coming back to your questions of when to use what:
If you want to provide a unified and global way of exception handling make use of
ControllerAdvice. It also eliminates code duplication which might be caused by ResponseStatusException.
In order to throw different error code and responses for the same exception, don't want to create custom exception classes and to avoid tight coupling make use of ResponseStatusException.
References:
Spring ResponseStatusException
Error Handling for REST with Spring
Overall it is better to use #ControllerAdvice if you are looking for a more unified solution but ResponseStatusException is also handy too in case you don't want to make different Exception classes and want to keep it simple.
for examples and more info you can refer to the following articles:
Spring Boot Exception Handling — #ControllerAdvice
Spring Boot Exception Handling — ResponseStatusException

Method Overriding in Exception handling

In exception handling, it is known that, if the super class method does not declare an exception, subclass overridden method cannot declare the checked exception but it can declare unchecked exception. Why so? consider the following example :
import java.io.*;
class Parent {
void msg() {
System.out.println("parent");
}
}
class TestExceptionChild extends Parent {
void msg() throws IOException {
System.out.println("TestExceptionChild");
}
public static void main(String args[]) {
Parent p = new TestExceptionChild();
p.msg();
}
}
What I have tried:
We get compilation error here. If I need to read a file in the overridden method "msg", then I have to mention "throws IOException" there. But java doesn't allow them. Can anyone explain this?
This happens because you are violating the Liskov substitution principle, i.e: you can't replace the instance of the superclass with one of the subclass because you are modifying the signature of the method msg in the father superclass.
In the more general class, the method msg doesn't throw any exception, and you want to modify the signature in the subclass, which is obviously unallowed, because it violates the contract of the override principal.
You need remember one thing that if you are using throws keyword than any exception arises will be forwarded into the calling chain and in case of overriding at compilation time compiler checks weather the overridden method is there in parent or not and JVM execute the child class method.
So,basically from parent the child method is called and hence it should be capable of handling checked exception if child method throws any exception otherwise CE..
I Hope It Helps :)

Jersey unable to catch any Jackson Exception

For my REST api I'm using jersey and ExceptionMapper to catch global exceptions.
It works well all the exception my app throws but I'm unable to catch exception thrown by jackson.
For example one of my endpoint accept an object that contains an enum. If the Json in the request has a value that is not in the enum jersey throw this exception back
Can not construct instance of my.package.MyEnum from String value 'HELLO': value not one of declared Enum instance names: [TEST, TEST2]
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#5922e236; line: 3, column: 1] (through reference chain: java.util.HashSet[0]->....)
Even though I have created this mapper
#Provider
#Component
public class JacksonExceptionMapper implements ExceptionMapper<JsonMappingException> {
#Override
public Response toResponse(JsonMappingException e) {
....
}
}
The code never reach this mapper.
Is there anything we need to do in order to catch these exceptions?
EDIT
Note: I have jus tried being less general and instead of JsonMappingException I use InvalidFormatException in this case the mapper is called. But I still don't understand because InvalidFormatException extends JsonMappingException and should be called as well
Had the same problem.
The problem is that JsonMappingExceptionMapper kicks in before your mapper. The actual exception is of class com.fasterxml.jackson.databind.exc.InvalidFormatException and the mapper defines com.fasterxml.jackson.jaxrs.base.JsonMappingException, so it's more specific to the exception.
You see, Jersey's exception handler looks to find the most accurate handler (see org.glassfish.jersey.internal.ExceptionMapperFactory#find(java.lang.Class, T)).
To override this behavior, simply disable the mapper from being used:
Using XML:
<init-param>
<param-name>jersey.config.server.disableAutoDiscovery</param-name>
<param-value>true</param-value>
</init-param>
Using code: resourceConfig.property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true); where resourceConfig is of type org.glassfish.jersey.server.ServerConfig.
You can also write your own specific mapper:
public class MyJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException>
But I think it's an over kill.
Hi it seems to exits an alternative answer now that does not require to disable Jersey AUTO_DISCOVERY feature.
Just annotate your own exception mapper with a #Priority(1) annotation. The lower the number, the higher the priority. Since Jackson's own mappers do not have any priority annotation, yours will be executed:
#Priority(1)
public class MyJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException>
Starting in version 2.29.1 [1], if you're registering the JacksonFeature, you can now do so without registering the exception mappers [2]:
register(JacksonFeature.withoutExceptionMappers());
[1] https://github.com/eclipse-ee4j/jersey/pull/4225
[2] https://eclipse-ee4j.github.io/jersey.github.io/apidocs/2.34/jersey/org/glassfish/jersey/jackson/JacksonFeature.html#withoutExceptionMappers--

JUnit - Catch an exception in the #After section

I have this scenario in which some tests can throw different exceptions.
#Test
public void addDevice(){
device.addDevice(); // this may throw exception 1
device.verifyStatus("Ready");
device.open(); // this may throw exception 2
device.verifyStatus("Open");
}
#Test
public void otherTest(){
device.act(); // this may throw exception 3
device.verifyStatus("Ready");
}
#After
public void tearDown(){
// handle the exception here
}
I want to handle those exceptions in the #After section without wrapping the test with try, catch.
Is that possible?
No, it is not possible.
You could wrap the test anyway with a try-catch-block. Then you could store the exception to a member variable instead of handling it.
In the #After method you can check whether the exception is null or not.
Due to your comment that you have hundreds of tests with this code I assume that this is set up logic which should actually be in an #Before method.
Thus, you could specify an external resource rule with a before and after method: https://github.com/junit-team/junit/wiki/Rules#externalresource-rules
In the before() method you perform the set up, catch and store the exceptions and in the after() method you handle them.
But does it make sense to handle the exception later? Can you run your test cases successfully if the set up fails?