All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zalando.problem.spring.common.AdviceTrait Maven / Gradle / Ivy

package org.zalando.problem.spring.common;

import org.apiguardian.api.API;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.zalando.problem.*;

import javax.annotation.Nullable;
import java.net.URI;
import java.util.Optional;

import static java.util.Arrays.asList;
import static org.apiguardian.api.API.Status.INTERNAL;
import static org.apiguardian.api.API.Status.MAINTAINED;
import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;
import static org.zalando.problem.spring.common.Lists.lengthOfTrailingPartialSubList;

/**
 * 

* Advice traits are simple interfaces that provide a single method with a default * implementation. They are used to provide {@link ExceptionHandler} implementations to be used in * Spring Controllers and/or in a {@link ControllerAdvice}. Clients can choose which traits they what to * use à la carte. *

*

* Advice traits are grouped in packages, based on they use cases. Every package has a composite advice trait that * bundles all traits of that package. *

* * @see ControllerAdvice * @see ExceptionHandler * @see Throwable * @see Exception * @see Problem */ @API(status = INTERNAL) public interface AdviceTrait { default ThrowableProblem toProblem(final Throwable throwable) { final StatusType status = Optional.ofNullable(resolveResponseStatus(throwable)) .map(ResponseStatusAdapter::new) .orElse(Status.INTERNAL_SERVER_ERROR); return toProblem(throwable, status); } @API(status = MAINTAINED) default ResponseStatus resolveResponseStatus(final Throwable type) { @Nullable final ResponseStatus candidate = findMergedAnnotation(type.getClass(), ResponseStatus.class); return candidate == null && type.getCause() != null ? resolveResponseStatus(type.getCause()) : candidate; } default ThrowableProblem toProblem(final Throwable throwable, final StatusType status) { return toProblem(throwable, status, Problem.DEFAULT_TYPE); } default ThrowableProblem toProblem(final Throwable throwable, final StatusType status, final URI type) { final ThrowableProblem problem = prepare(throwable, status, type).build(); final StackTraceElement[] stackTrace = createStackTrace(throwable); problem.setStackTrace(stackTrace); return problem; } default ProblemBuilder prepare(final Throwable throwable, final StatusType status, final URI type) { return Problem.builder() .withType(type) .withTitle(status.getReasonPhrase()) .withStatus(status) .withDetail(throwable.getMessage()) .withCause(Optional.ofNullable(throwable.getCause()) .filter(cause -> isCausalChainsEnabled()) .map(this::toProblem) .orElse(null)); } default StackTraceElement[] createStackTrace(final Throwable throwable) { final Throwable cause = throwable.getCause(); if (cause == null || !isCausalChainsEnabled()) { return throwable.getStackTrace(); } else { final StackTraceElement[] next = cause.getStackTrace(); final StackTraceElement[] current = throwable.getStackTrace(); final int length = current.length - lengthOfTrailingPartialSubList(asList(next), asList(current)); final StackTraceElement[] stackTrace = new StackTraceElement[length]; System.arraycopy(current, 0, stackTrace, 0, length); return stackTrace; } } default boolean isCausalChainsEnabled() { return false; } default ResponseEntity process(final ResponseEntity entity) { return entity; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy