Search in sources :

Example 1 with ExceptionHandler

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();
            }
        }
    }
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) ServerFilterChain(io.micronaut.http.filter.ServerFilterChain) BeanContext(io.micronaut.context.BeanContext) KotlinExecutableMethodUtils.isKotlinFunctionReturnTypeUnit(io.micronaut.inject.util.KotlinExecutableMethodUtils.isKotlinFunctionReturnTypeUnit) LoggerFactory(org.slf4j.LoggerFactory) HttpHeaders(io.micronaut.http.HttpHeaders) Internal(io.micronaut.core.annotation.Internal) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) HttpStatus(io.micronaut.http.HttpStatus) MediaType(io.micronaut.http.MediaType) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted) HttpResponse(io.micronaut.http.HttpResponse) MethodReference(io.micronaut.inject.MethodReference) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) CompletionException(java.util.concurrent.CompletionException) HttpFilter(io.micronaut.http.filter.HttpFilter) RequestArgumentSatisfier(io.micronaut.http.server.binding.RequestArgumentSatisfier) List(java.util.List) RouteInfo(io.micronaut.web.router.RouteInfo) BeanCreationException(io.micronaut.context.exceptions.BeanCreationException) Optional(java.util.Optional) HttpAttributes(io.micronaut.http.HttpAttributes) Pattern(java.util.regex.Pattern) RouteMatch(io.micronaut.web.router.RouteMatch) UnsatisfiedRouteException(io.micronaut.web.router.exceptions.UnsatisfiedRouteException) LocalDateTime(java.time.LocalDateTime) CompletableFuture(java.util.concurrent.CompletableFuture) Scheduler(reactor.core.scheduler.Scheduler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Supplier(java.util.function.Supplier) ExceptionHandler(io.micronaut.http.server.exceptions.ExceptionHandler) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ArrayList(java.util.ArrayList) ErrorContext(io.micronaut.http.server.exceptions.response.ErrorContext) Nullable(io.micronaut.core.annotation.Nullable) ReturnType(io.micronaut.core.type.ReturnType) Schedulers(reactor.core.scheduler.Schedulers) Argument(io.micronaut.core.type.Argument) HttpRequest(io.micronaut.http.HttpRequest) ServerRequestContext(io.micronaut.http.context.ServerRequestContext) ErrorResponseProcessor(io.micronaut.http.server.exceptions.response.ErrorResponseProcessor) ExecutorService(java.util.concurrent.ExecutorService) HttpStatusException(io.micronaut.http.exceptions.HttpStatusException) HttpMethod(io.micronaut.http.HttpMethod) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) ExecutorSelector(io.micronaut.scheduling.executor.ExecutorSelector) Publisher(org.reactivestreams.Publisher) Mono(reactor.core.publisher.Mono) IOException(java.io.IOException) BeanType(io.micronaut.inject.BeanType) ExecutionException(java.util.concurrent.ExecutionException) NonNull(io.micronaut.core.annotation.NonNull) Flux(reactor.core.publisher.Flux) ContinuationArgumentBinder(io.micronaut.http.bind.binders.ContinuationArgumentBinder) KotlinUtils.isKotlinCoroutineSuspended(io.micronaut.core.util.KotlinUtils.isKotlinCoroutineSuspended) BeanDefinition(io.micronaut.inject.BeanDefinition) Router(io.micronaut.web.router.Router) Collections(java.util.Collections) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) ExecutableMethod(io.micronaut.inject.ExecutableMethod) BeanDefinition(io.micronaut.inject.BeanDefinition) ExceptionHandler(io.micronaut.http.server.exceptions.ExceptionHandler) List(java.util.List) ArrayList(java.util.ArrayList) ExecutionException(java.util.concurrent.ExecutionException) Collections(java.util.Collections) HttpRequest(io.micronaut.http.HttpRequest) AtomicReference(java.util.concurrent.atomic.AtomicReference) ReturnType(io.micronaut.core.type.ReturnType) CompletionException(java.util.concurrent.CompletionException) ExecutorService(java.util.concurrent.ExecutorService)

Aggregations

BeanContext (io.micronaut.context.BeanContext)1 BeanCreationException (io.micronaut.context.exceptions.BeanCreationException)1 Internal (io.micronaut.core.annotation.Internal)1 NonNull (io.micronaut.core.annotation.NonNull)1 Nullable (io.micronaut.core.annotation.Nullable)1 Publishers (io.micronaut.core.async.publisher.Publishers)1 ReferenceCounted (io.micronaut.core.io.buffer.ReferenceCounted)1 Argument (io.micronaut.core.type.Argument)1 ReturnType (io.micronaut.core.type.ReturnType)1 KotlinUtils.isKotlinCoroutineSuspended (io.micronaut.core.util.KotlinUtils.isKotlinCoroutineSuspended)1 HttpAttributes (io.micronaut.http.HttpAttributes)1 HttpHeaders (io.micronaut.http.HttpHeaders)1 HttpMethod (io.micronaut.http.HttpMethod)1 HttpRequest (io.micronaut.http.HttpRequest)1 HttpResponse (io.micronaut.http.HttpResponse)1 HttpStatus (io.micronaut.http.HttpStatus)1 MediaType (io.micronaut.http.MediaType)1 MutableHttpHeaders (io.micronaut.http.MutableHttpHeaders)1 MutableHttpResponse (io.micronaut.http.MutableHttpResponse)1 ContinuationArgumentBinder (io.micronaut.http.bind.binders.ContinuationArgumentBinder)1