Skip to content

Commit

Permalink
Register a low-priority exception mapper to log internal errors in Je…
Browse files Browse the repository at this point in the history
…rsey that are otherwise lost. (#5082)
  • Loading branch information
spericas authored Oct 5, 2022
1 parent 01fe7c1 commit 4633b5e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,16 @@
import io.helidon.reactive.webserver.jersey.HelidonHK2InjectionManagerFactory.InjectionManagerWrapper;
import io.helidon.tracing.SpanContext;

import jakarta.annotation.Priority;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Configurable;
import jakarta.ws.rs.core.Configuration;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.ext.ExceptionMapper;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.internal.inject.InjectionManager;
Expand Down Expand Up @@ -137,6 +142,9 @@ private JerseySupport(Builder builder) {
serviceShutdownHook = new Thread(service::shutdownNow);
Runtime.getRuntime().addShutdownHook(serviceShutdownHook);

// Register an error mapper to log internal exceptions in Jersey
builder.resourceConfig.register(InternalErrorMapper.class);

// make sure we have a wrapped async executor as well
if (builder.asyncExecutorService == null) {
// create a new one from configuration
Expand Down Expand Up @@ -503,6 +511,15 @@ private Builder(Application application) {
}
}

/**
* This method is used for testing only.
*
* @return underlying resource config.
*/
ResourceConfig resourceConfig() {
return resourceConfig;
}

/**
* Jersey Module builder class for convenient creating {@link JerseySupport}.
*
Expand Down Expand Up @@ -662,4 +679,19 @@ public void reload(ResourceConfig configuration) {
throw new UnsupportedOperationException("Reloading is not supported in Helidon");
}
}

/**
* A low priority mapper to catch internal exceptions in Jersey and log them.
* Otherwise, these errors can get lost and never reported by Helidon. One example
* is a {@code ClassNotFoundException} exception in Jersey's code.
*/
@Priority(Priorities.USER + 1000)
static class InternalErrorMapper implements ExceptionMapper<InternalServerErrorException> {

@Override
public Response toResponse(InternalServerErrorException e) {
LOGGER.log(Level.FINE, "Internal error thrown by Jersey", e);
return Response.status(500).build();
}
}
}
2 changes: 1 addition & 1 deletion reactive/webserver/jersey/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@
provides InjectionManagerFactory with HelidonHK2InjectionManagerFactory;

// reflection access from jersey injection
opens io.helidon.reactive.webserver.jersey to org.glassfish.hk2.utilities, org.glassfish.hk2.locator;
opens io.helidon.reactive.webserver.jersey to org.glassfish.hk2.utilities, org.glassfish.hk2.locator, weld.core.impl;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
import static io.helidon.reactive.webserver.jersey.JerseySupport.basePath;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
Expand Down Expand Up @@ -338,6 +340,14 @@ public void testJerseyProperties() {
assertThat(System.getProperty(IGNORE_EXCEPTION_RESPONSE), is("true"));
}

@Test
public void testInternalErrorMapper() {
JerseySupport.Builder builder = JerseySupport.builder();
JerseySupport jerseySupport = builder.build();
assertThat(jerseySupport, is(notNullValue()));
assertThat(builder.resourceConfig().getClasses(), contains(JerseySupport.InternalErrorMapper.class));
}

static class PathMockup implements ServerRequest.Path {
private final String absolutePath;
private final String path;
Expand Down

0 comments on commit 4633b5e

Please sign in to comment.