6

I've been able to find endless amounts of tutorials on how to catch unhandled exceptions in Spring MVC or Spring REST, but what I want to know is how to catch unhandled exceptions without using the Spring Web framework at all.

I am writing an application which does not have a web component, and I am not going to import Spring Web only for exception handling.

When a @Service throws an exception that goes unhandled, I need to catch it so that I can log it properly to Raygun.

For example, consider this method in a Service that purposely throws an uncaught exception:

@Scheduled(fixedDelay = 100)
public void doSomething() {
    throw new RuntimeException("Uh oh!");
}

Its output will be:

2017-08-16 00:19:40.202 ERROR 91168 --- [pool-1-thread-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task.

java.lang.RuntimeException: Uh oh!
    at com.mitchtalmadge.example.ExampleService.doSomething(ClassSyncService.java:48) ~[classes/:na]
    at com.mitchtalmadge.example.ExampleService$$FastClassBySpringCGLIB$$1dd464d8.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:669)
    ...

How do I catch that?

Is there no easy way to do this?

traskjd
  • 1,008
  • 5
  • 7
Mitch Talmadge
  • 4,638
  • 3
  • 26
  • 44
  • Why don't use **try-catch**? – Mehraj Malik Aug 16 '17 at 06:13
  • 1
    Can you explain in more detail what you mean by "a @Service throws an exception that goes unhandled"? Who calls the code that throws the exception? – Oleg Aug 16 '17 at 06:13
  • @MehrajMalik Try-catch where? Around every method in every service? The point of an uncaught exception handler is that it catches the exceptions you didn't anticipate with a try-catch. – Mitch Talmadge Aug 16 '17 at 06:15
  • @Oleg One case would be a Scheduled method, but there are other places they can be called. This application in particular is a Discord bot, so when events are received, such as a user posting a message, it will call methods on various Services. When they throw exceptions, all it does is print to the console -- I never know about it. – Mitch Talmadge Aug 16 '17 at 06:15
  • @Oleg I've added an example to the question. – Mitch Talmadge Aug 16 '17 at 06:22
  • ok, if it's only scheduled methods than you can add an exception handler. That's [easy](https://stackoverflow.com/a/45659602/1398418). If you want to catch any exception thrown from any service that's more difficult, maybe can be done with aop. – Oleg Aug 16 '17 at 06:30

2 Answers2

8

You can define an aspect. Using Java-based configuration it will look like this:

@Aspect
public class ExceptionHandler {

    @AfterThrowing(pointcut="execution(* your.base.package..*.*(..))", throwing="ex")
    public void handleError(Exception ex) {
        //handling the exception
     }
}

If you need to inject a bean, add the @Component annotation:

@Aspect
@Component
public class ExceptionHandler {

    @Autowired
    private NotificationService notificationService;

    @AfterThrowing(pointcut="execution(* your.base.package..*.*(..))", throwing="ex")
    public void handleError(Exception ex) {
        notificationService.sendMessage(ex.getMessage());
     }
}
Ilya Lysenko
  • 1,772
  • 15
  • 24
  • It is also possible to use `@Around` instead of `@AfterThrowing`. This allows for proper exception handling, even for those cases for which Spring already provides an aspect-based handler, such as Hibernate exceptions. https://www.mscharhag.com/java/aspectj-exception-translation – gscaparrotti Apr 26 '20 at 17:35
3

You can use the aop in spirngframework,first you should config the aop configuration.

<bean id="aspect" class="com.zhuyiren.Main"/>

<aop:config>
    <aop:aspect ref="aspect">
        <aop:after-throwing method="after" throwing="ex" pointcut="execution(* com.zhuyiren.service..*.*(..)),args(ex)"/>
    </aop:aspect>
</aop:config>

and then you should declare a aspect class has method be named after:

public class Main {

public void after(JoinPoint point,Throwable ex){
    System.out.println(point);
    System.out.println("catch error:"+ex.getMessage());
}

When the service is throwning a error,the method will catch and resolve it. In my Sevice,i make a ArithmeticException,and run the application,the print is:

execution(TeacherInfo com.zhuyiren.service.TeacherService.getTeacherInfo())
catch error:/ by zero

Of course,the above configuration is depends on xml,you also can do it through Annotation such as @Aspect,@Pointcut,@AfterThrowing.

dabaicai
  • 999
  • 8
  • 9