use of io.micronaut.http.server.exceptions.ExceptionHandler in project micronaut-core by micronaut-projects.
the class RouteExecutor method onError.
/**
* Creates a response publisher to represent the response after being handled
* by any available error route or exception handler.
*
* @param t The exception that occurred
* @param httpRequest The request that caused the exception
* @return A response publisher
*/
public Flux<MutableHttpResponse<?>> onError(Throwable t, HttpRequest<?> httpRequest) {
// find the origination of of the route
Class declaringType = httpRequest.getAttribute(HttpAttributes.ROUTE_INFO, RouteInfo.class).map(RouteInfo::getDeclaringType).orElse(null);
final Throwable cause;
// top level exceptions returned by CompletableFutures. These always wrap the real exception thrown.
if ((t instanceof CompletionException || t instanceof ExecutionException) && t.getCause() != null) {
cause = t.getCause();
} else {
cause = t;
}
RouteMatch<?> errorRoute = findErrorRoute(cause, declaringType, httpRequest);
if (errorRoute != null) {
if (serverConfiguration.isLogHandledExceptions()) {
logException(cause);
}
try {
AtomicReference<HttpRequest<?>> requestReference = new AtomicReference<>(httpRequest);
return buildRouteResponsePublisher(requestReference, Flux.just(errorRoute)).doOnNext(response -> response.setAttribute(HttpAttributes.EXCEPTION, cause)).onErrorResume(throwable -> createDefaultErrorResponsePublisher(requestReference.get(), throwable));
} catch (Throwable e) {
return createDefaultErrorResponsePublisher(httpRequest, e).flux();
}
} else {
Optional<BeanDefinition<ExceptionHandler>> optionalDefinition = beanContext.findBeanDefinition(ExceptionHandler.class, Qualifiers.byTypeArgumentsClosest(cause.getClass(), Object.class));
if (optionalDefinition.isPresent()) {
BeanDefinition<ExceptionHandler> handlerDefinition = optionalDefinition.get();
final Optional<ExecutableMethod<ExceptionHandler, Object>> optionalMethod = handlerDefinition.findPossibleMethods("handle").findFirst();
RouteInfo<Object> routeInfo;
if (optionalMethod.isPresent()) {
routeInfo = new ExecutableRouteInfo(optionalMethod.get(), true);
} else {
routeInfo = new RouteInfo<Object>() {
@Override
public ReturnType<?> getReturnType() {
return ReturnType.of(Object.class);
}
@Override
public Class<?> getDeclaringType() {
return handlerDefinition.getBeanType();
}
@Override
public boolean isErrorRoute() {
return true;
}
@Override
public List<MediaType> getProduces() {
return MediaType.fromType(getDeclaringType()).map(Collections::singletonList).orElse(Collections.emptyList());
}
};
}
Flux<MutableHttpResponse<?>> reactiveSequence = Flux.defer(() -> {
ExceptionHandler handler = beanContext.getBean(handlerDefinition);
try {
if (serverConfiguration.isLogHandledExceptions()) {
logException(cause);
}
Object result = handler.handle(httpRequest, cause);
return createResponseForBody(httpRequest, result, routeInfo);
} catch (Throwable e) {
return createDefaultErrorResponsePublisher(httpRequest, e);
}
});
final ExecutorService executor = findExecutor(routeInfo);
if (executor != null) {
reactiveSequence = applyExecutorToPublisher(reactiveSequence, executor);
}
return reactiveSequence.doOnNext(response -> response.setAttribute(HttpAttributes.EXCEPTION, cause)).onErrorResume(throwable -> createDefaultErrorResponsePublisher(httpRequest, throwable));
} else {
if (isIgnorable(cause)) {
logIgnoredException(cause);
return Flux.empty();
} else {
return createDefaultErrorResponsePublisher(httpRequest, cause).flux();
}
}
}
}
Aggregations