2

I was trying to handle global exception but its not working without method call from REST API.

I have following code

@SpringBootApplication 
public class LogReduceDemoApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(LogReduceDemoApplication.class, args);
        System.out.println(".......Started......");
        LogReduceDemoApplication.testException();
    }

    public static void testException() throws Exception {
        throw new Exception("testException...");
    }
}

Exception Handler

@ControllerAdvice
public class ExceptionHelper {

    static final Logger logger = LoggerFactory.getLogger(ExceptionHelper.class.getName());

    @ExceptionHandler(value = { NullPointerException.class,Exception.class })
    public ResponseEntity<Object> handleException(Exception ex) {
        System.out.println("Inside handleException...");
        String msg="ex="+ex+", ex.getMessage()="+ex.getMessage();
        System.out.println("Exception Msg: "+ msg);
        return new ResponseEntity<Object>(msg, HttpStatus.BAD_REQUEST);
    }
}

When I am calling LogReduceDemoApplication.testException() method from REST controller then it is triggering exception handler. But when there is a call to the same method using main() function its not triggering Exception handler instead it is printing all exception details.

How to use exception handler for the method call from main function(not from REST controller)?

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
stackUser
  • 545
  • 3
  • 9
  • 21
  • 3
    @ControllerAdvice methods only apply to controllers. – tgdavies May 21 '21 at 07:11
  • Yes...I am trying to find a way to handle exception globally for non controller code(example method call from main method or cron shedule etc) – stackUser May 21 '21 at 07:14
  • Well you can use that handling, but then again - if its not in a REST-Context, it should not return a response object or anything like that. Instead it could be void and could contain some logic to handle and log the issues. Especially when handling request / response exceptions, which indeed return response objects you need to be vary cautios since manipulating the response object after returning the response (e.g. a already started file download from your rest-controller) itself leads to an exception and therefor has to be handled in another fashion – phaen May 21 '21 at 08:09
  • @phaen It should not in REST context....but everywhere I see REST based solution only...How to handle exception globally without REST context? – stackUser May 21 '21 at 09:00
  • Its always in a "rest context" since its handled exceptions thrown within controllers / rest-controllers. That means its imo not a thing to handle "global npe". But rather have specific exceptions (e.g. by extending runtimeexceptions) which your controllers will throw and which are handled in the same way via those exception handler. It shall make it easier to treat exceptions the same way, but its not meant to be used on any exception thrown within your app. Its meant to be triggered on purpose handling specific exceptions in a specific way. – phaen May 21 '21 at 11:54

2 Answers2

3

You should try to use Aspects. Something like this:

@Component
@Aspect
public class LoggingAspect {    
       
    private final Logger logger =
            LoggerFactory.getLogger(getClass().getSimpleName());               

    @Around("execution(* {YOU_PACKAGE_HERE}..*.*(..))")
    public Object someOperationAround(ProceedingJoinPoint pjp) throws Throwable {
        Object result;
        try {
            long t1 = System.currentTimeMillis();
            logger.debug("Calling {} with args: {} ",
                    pjp.getSignature().toShortString(),
                    pjp.getArgs());
            result = pjp.proceed();
            double duration = (System.currentTimeMillis() - t1) / 1000.;
            logger.debug("{} - Time elapsed: {}sec",
                    pjp.getSignature().toShortString(), duration);
        } catch (Throwable ex) {
            logger.warn("When call {} with args: {} Exception thrown: {}",
                    pjp.getSignature().toShortString(),
                    pjp.getArgs(), ex.getMessage());
            throw ex;
        }
        return result;
    }

}

Or @AfterThrowing instead of @Around if you need to catch only exceptions.

    @AfterThrowing(pointcut="execution(* {YOU_PACKAGE_HERE}..*.*(..)))", throwing="theExc")
    public void afterThrowingAdvice(JoinPoint theJoinPoint, Throwable theExc) {

        String method = theJoinPoint.getSignature().toShortString();
        System.out.println("\n=====>>> Executing @AfterThrowing on method: " + method);
    
        // log the exception
        System.out.println("\n=====>>> The exception is: " + theExc);    
    }
tuuka
  • 33
  • 6
0

You can't. It also does not make sense. The @ExceptionHandler method is returning a ResponseEntity that does not make sense outside the REST context.

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
  • How to do the same outside the REST context? I was searching the solution but everywhere I see REST based exception handling – stackUser May 21 '21 at 08:55
  • `try {} catch() {}`? – EricSchaefer May 21 '21 at 11:43
  • 1
    I dont want to add try catch in all functions/files – stackUser May 21 '21 at 11:46
  • But that's how it works in Java. The default exception handler for Spring controller is a specialty of Spring MVC. Otherwise use AOP (see the answer by @tuuka). This is what Spring is doing under hood as well. – EricSchaefer May 21 '21 at 11:50
  • I am trying with AOP but its printing default exception logs that I dont want....see this posted questions for the same https://stackoverflow.com/q/67635714/9024680 – stackUser May 21 '21 at 11:52