Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.ExceptionMapper;

import org.jboss.logging.Logger;

import io.quarkiverse.httpproblem.postprocessing.PostProcessorsRegistry;
import io.quarkiverse.httpproblem.postprocessing.ProblemContext;

public abstract class ExceptionMapperBase<E extends Throwable> implements ExceptionMapper<E> {

private static final Logger LOG = Logger.getLogger(ExceptionMapperBase.class);

private PostProcessorsRegistry postProcessorsRegistry;

@Context
Expand All @@ -28,7 +32,22 @@ protected ExceptionMapperBase(PostProcessorsRegistry postProcessorsRegistry) {
public final Response toResponse(E exception) {
Objects.requireNonNull(postProcessorsRegistry,
"PostProcessorsRegistry not injected — mapper must be instantiated via CDI");
HttpProblem problem = toProblem(exception);

HttpProblem problem;
try {
problem = toProblem(exception);
} catch (Exception e) {
LOG.errorf(e, "toProblem() failed for %s, falling back to generic 500",
exception.getClass().getName());
problem = HttpProblem.valueOf(Response.Status.INTERNAL_SERVER_ERROR);
}

if (problem == null) {
LOG.errorf("toProblem() returned null for %s, falling back to generic 500",
exception.getClass().getName());
problem = HttpProblem.valueOf(Response.Status.INTERNAL_SERVER_ERROR);
}

ProblemContext context = ProblemContext.of(exception, uriInfo);
HttpProblem finalProblem = postProcessorsRegistry.applyPostProcessing(problem, context);
return finalProblem.toResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ protected HttpProblem(Builder builder) {
this.headers = Collections.unmodifiableMap(Optional.ofNullable(builder.headers).orElseGet(LinkedHashMap::new));
}

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}

private static String createMessage(String title, String detail) {
return Stream.of(title, detail)
.filter(Objects::nonNull)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.quarkiverse.httpproblem;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;

import jakarta.ws.rs.core.Response;

import org.junit.jupiter.api.Test;

import io.quarkiverse.httpproblem.postprocessing.PostProcessorsRegistry;

class ExceptionMapperBaseTest {

PostProcessorsRegistry registry = new PostProcessorsRegistry(List.of());

@Test
void shouldFallBackToGeneric500WhenToProblemThrows() {
ExceptionMapperBase<RuntimeException> mapper = new ExceptionMapperBase<>(registry) {
@Override
protected HttpProblem toProblem(RuntimeException exception) {
throw new IllegalStateException("mapper bug");
}
};

Response response = mapper.toResponse(new RuntimeException("original"));

assertThat(response.getStatus()).isEqualTo(500);
}

@Test
void shouldFallBackToGeneric500WhenToProblemReturnsNull() {
ExceptionMapperBase<RuntimeException> mapper = new ExceptionMapperBase<>(registry) {
@Override
protected HttpProblem toProblem(RuntimeException exception) {
return null;
}
};

Response response = mapper.toResponse(new RuntimeException("original"));

assertThat(response.getStatus()).isEqualTo(500);
}

@Test
void shouldProcessNormallyWhenToProblemSucceeds() {
ExceptionMapperBase<RuntimeException> mapper = new ExceptionMapperBase<>(registry) {
@Override
protected HttpProblem toProblem(RuntimeException exception) {
return HttpProblem.valueOf(Response.Status.BAD_REQUEST);
}
};

Response response = mapper.toResponse(new RuntimeException("bad input"));

assertThat(response.getStatus()).isEqualTo(400);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,10 @@ void builderShouldNotAllowAddingReservedProperties(String property) {
.isInstanceOf(IllegalArgumentException.class);
}

@Test
void shouldNotCaptureStackTrace() {
HttpProblem problem = HttpProblem.valueOf(Response.Status.BAD_REQUEST);
assertThat(problem.getStackTrace()).isEmpty();
}

}