Currently I am working on a small system to log all the uncaught exceptions and store them into a database for further debugging / development. To do so I am using an UncaughtExceptionHandler for a specific thread:
public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler{
@Autowired
private LoggedExceptionService service;
public GlobalExceptionHandler() {
}
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println("IN UNCAUGHTEXCEPTION METHOD");
this.service.saveException(new LoggedException(e));
}
}
As you can see the field service
is injected and when I catch an exception, then I get a NullPointerException because the field is null.
The main problem is the usage of the GlobalExceptionHandler. If I inject using the constructor (like in this code snippet):
private LoggedExceptionService service;
@Autowired
public GlobalExceptionHandler(LoggedExceptionService service) {
this.service = service;
}
then the field is not null, but then I can not declare it as the exception handler, because I can not autowire it to java-native methods. The call would be:
Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler());
Is there a possibility to autowire the handler to the thread method or what would be a good way to go?
Make it a component and set the default exception handler in an @PostConstruct
method.
@Component
public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler{
@Autowired
private LoggedExceptionService service;
public GlobalExceptionHandler() {
}
@PostConstruct
public void init(){
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println("IN UNCAUGHTEXCEPTION METHOD");
this.service.saveException(new LoggedException(e));
}
}
This allows you to automatically set the handler as methods annotated with @PostConstruct
in components are automatically executed on startup.
Making GlobalExceptionHandler
a spring component also allows to autowire service
that would never been set otherwise. Anyways, I would recommend you to use constructor autowiring:
@Component
public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler{
private final LoggedExceptionService service;
@Autowired // @Autowired is actually not necessary if this is the only constructor
public GlobalExceptionHandler(LoggedExceptionService service) {
this.service=service
}
@PostConstruct
public void init(){
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println("IN UNCAUGHTEXCEPTION METHOD");
this.service.saveException(new LoggedException(e));
}
}