@GraphQlExceptionHandler methods declared in controllers or @ControllerAdvice are now supported as of https://github.com/spring-projects/spring-graphql/issues/160 as a built-in feature of AnnotatedControllerConfigurer, and this is automatically applied to controller method invocations with no further configuration needed.
To apply @ControllerAdvice exception handling to other (non-controller) DataFetcher implementations like QueryDslDataFetcher, QueryByExampleDataFetcher, and others, it is necessary to obtain a DataFetcherExceptionResolver from AnnotatedControllerConfigurer and plug that into the GraphQlSource builder, and so a small update in the Boot starter is required for this.
Comment From: wilkinsona
This change, assuming I have implemented it as intended, seems to break handling of AccessDeniedException for which there's no @GraphQlExceptionHandler method. Rather than the exception reaching SecurityDataFetcherExceptionResolver, AnnotatedControllerExceptionResolver aborts the resolution by returning Mono.error(ex) because methodHolder is null:
if (methodHolder == null) {
return Mono.error(ex);
}
Perhaps it wouldn't be a problem if SecurityDataFetcherExceptionResolver was called first but it does not appear to be ordered so I can't see how to ensure that AnnotatedControllerExceptionResolver goes after it. I'm also not sure that's desirable as it would then prevent a @GraphQlExceptionHandler method for AccessDeniedException from overriding Security's resolver.
Comment From: rstoyanchev
A DataFetcherExceptionResolver can leave the exception unresolved and yield to other resolvers, and that's the intent with Mono.error(ex), i.e. if there is no suitable annotated exception handler, let it be handled further down the chain. The contract though says it should return an empty Mono for that to happen, so this looks like a bug.
AnnotatedControllerExceptionResolver is also used at the point of controller method invocation where we know which controller method raised the exception, and at that level we want to propagate the error further, and hence the Mono#error there. At the level of a DataFetcherExceptionResolver however we need to return an empty Mono.
I'll reopen https://github.com/spring-projects/spring-graphql/issues/160 to consider how to fix this. Thanks for the timely feedback!