Skip to content

Commit 7d3588d

Browse files
committed
Introduce "quarkus.rest.exception-mapping.disable-mapper-for"
Relates to #36155
1 parent 2d6c672 commit 7d3588d

File tree

4 files changed

+106
-2
lines changed

4 files changed

+106
-2
lines changed

extensions/resteasy-reactive/rest-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ResteasyReactiveConfig.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package io.quarkus.resteasy.reactive.common.runtime;
22

3+
import java.util.List;
4+
import java.util.Optional;
5+
36
import io.quarkus.runtime.annotations.ConfigPhase;
47
import io.quarkus.runtime.annotations.ConfigRoot;
58
import io.quarkus.runtime.configuration.MemorySize;
@@ -11,6 +14,11 @@
1114
@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
1215
public interface ResteasyReactiveConfig {
1316

17+
/**
18+
* Exception mapping configuration.
19+
*/
20+
ExceptionMappingConfig exceptionMapping();
21+
1422
/**
1523
* The amount of memory that can be used to buffer input before switching to
1624
* blocking IO, up to {@code Long.MAX_VALUE} bytes.
@@ -81,4 +89,15 @@ public interface ResteasyReactiveConfig {
8189
*/
8290
@WithDefault("true")
8391
boolean removesTrailingSlash();
92+
93+
/**
94+
* Configuration for exception mapping.
95+
*/
96+
interface ExceptionMappingConfig {
97+
/**
98+
* A list of exception mapper classes that should be disabled.
99+
* This allows users to override the default built-in exception mappers provided by Quarkus extensions.
100+
*/
101+
Optional<List<String>> disableMapperFor();
102+
}
84103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.quarkus.resteasy.reactive.jackson.deployment.test;
2+
3+
import java.util.function.Supplier;
4+
5+
import jakarta.ws.rs.core.Response;
6+
import jakarta.ws.rs.ext.ExceptionMapper;
7+
import jakarta.ws.rs.ext.Provider;
8+
9+
import org.jboss.shrinkwrap.api.ShrinkWrap;
10+
import org.jboss.shrinkwrap.api.spec.JavaArchive;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.RegisterExtension;
13+
14+
import com.fasterxml.jackson.databind.JsonMappingException;
15+
16+
import io.quarkus.test.QuarkusUnitTest;
17+
import io.restassured.RestAssured;
18+
19+
public class ExceptionInReaderWithDisabledBuiltInMapperTest {
20+
21+
@RegisterExtension
22+
static QuarkusUnitTest test = new QuarkusUnitTest()
23+
.setArchiveProducer(new Supplier<>() {
24+
@Override
25+
public JavaArchive get() {
26+
return ShrinkWrap.create(JavaArchive.class)
27+
.addClasses(FroMage.class, FroMageEndpoint.class, CustomJsonMappingExceptionMapper.class);
28+
}
29+
}).overrideConfigKey("quarkus.rest.exception-mapping.disable-mapper-for",
30+
"io.quarkus.resteasy.reactive.jackson.runtime.mappers.BuiltinMismatchedInputExceptionMapper");
31+
32+
@Test
33+
public void test() {
34+
RestAssured.with().contentType("application/json").body("{\"price\": \"ten\"}").put("/fromage")
35+
.then().statusCode(888);
36+
}
37+
38+
@Provider
39+
public static class CustomJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
40+
41+
@Override
42+
public Response toResponse(JsonMappingException exception) {
43+
return Response.status(888).entity("Custom mapper handled: " + exception.getMessage()).build();
44+
}
45+
}
46+
}

extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveScanningProcessor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import io.quarkus.resteasy.reactive.common.deployment.ApplicationResultBuildItem;
6666
import io.quarkus.resteasy.reactive.common.deployment.ResourceInterceptorsContributorBuildItem;
6767
import io.quarkus.resteasy.reactive.common.deployment.ResourceScanningResultBuildItem;
68+
import io.quarkus.resteasy.reactive.common.runtime.ResteasyReactiveConfig;
6869
import io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem;
6970
import io.quarkus.resteasy.reactive.server.spi.UnwrappedExceptionBuildItem;
7071
import io.quarkus.resteasy.reactive.spi.ContainerRequestFilterBuildItem;
@@ -189,11 +190,20 @@ public ExceptionMappersBuildItem scanForExceptionMappers(CombinedIndexBuildItem
189190
BuildProducer<AdditionalBeanBuildItem> additionalBeanBuildItemBuildProducer,
190191
BuildProducer<ReflectiveClassBuildItem> reflectiveClassBuildItemBuildProducer,
191192
List<ExceptionMapperBuildItem> mappers, List<UnwrappedExceptionBuildItem> unwrappedExceptions,
192-
Capabilities capabilities) {
193+
Capabilities capabilities,
194+
ResteasyReactiveConfig config) {
193195
AdditionalBeanBuildItem.Builder beanBuilder = AdditionalBeanBuildItem.builder().setUnremovable();
194196
ExceptionMapping exceptions = ResteasyReactiveExceptionMappingScanner
195197
.scanForExceptionMappers(combinedIndexBuildItem.getComputingIndex(), applicationResultBuildItem.getResult());
196198

199+
if (config.exceptionMapping().disableMapperFor().isPresent()) {
200+
for (String disabledMapper : config.exceptionMapping().disableMapperFor().get()) {
201+
if (disabledMapper != null && !disabledMapper.isEmpty()) {
202+
exceptions.addDisabledMapper(disabledMapper);
203+
}
204+
}
205+
}
206+
197207
exceptions.addBlockingProblem(BlockingOperationNotAllowedException.class);
198208
exceptions.addBlockingProblem(BlockingNotAllowedException.class);
199209
for (UnwrappedExceptionBuildItem bi : unwrappedExceptions) {

independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ExceptionMapping.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import java.util.ArrayList;
44
import java.util.Collections;
55
import java.util.HashMap;
6+
import java.util.HashSet;
67
import java.util.List;
78
import java.util.Map;
9+
import java.util.Set;
810
import java.util.function.Function;
911
import java.util.function.Predicate;
1012
import java.util.function.Supplier;
@@ -31,6 +33,11 @@ public class ExceptionMapping {
3133
// this is going to be used when there are mappers that are removable at runtime
3234
final Map<String, List<ResourceExceptionMapper<? extends Throwable>>> runtimeCheckMappers = new HashMap<>();
3335

36+
/**
37+
* Exception mapper class names that should be disabled.
38+
*/
39+
final Set<String> disabledMappers = new HashSet<>();
40+
3441
/**
3542
* Exceptions that indicate an blocking operation was performed on an IO thread.
3643
* <p>
@@ -126,9 +133,17 @@ public Map<String, List<ResourceExceptionMapper<? extends Throwable>>> getRuntim
126133
return runtimeCheckMappers;
127134
}
128135

136+
public Set<String> getDisabledMappers() {
137+
return disabledMappers;
138+
}
139+
140+
public void addDisabledMapper(String mapperClassName) {
141+
disabledMappers.add(mapperClassName);
142+
}
143+
129144
public Map<String, ResourceExceptionMapper<? extends Throwable>> effectiveMappers() {
130145
if (runtimeCheckMappers.isEmpty()) {
131-
return mappers;
146+
return filterDisabledMappers(mappers);
132147
}
133148
Map<String, ResourceExceptionMapper<? extends Throwable>> result = new HashMap<>();
134149
for (var entry : runtimeCheckMappers.entrySet()) {
@@ -147,6 +162,20 @@ public Map<String, ResourceExceptionMapper<? extends Throwable>> effectiveMapper
147162
}
148163
}
149164
result.putAll(mappers);
165+
return filterDisabledMappers(result);
166+
}
167+
168+
private Map<String, ResourceExceptionMapper<? extends Throwable>> filterDisabledMappers(
169+
Map<String, ResourceExceptionMapper<? extends Throwable>> mappers) {
170+
if (disabledMappers.isEmpty()) {
171+
return mappers;
172+
}
173+
Map<String, ResourceExceptionMapper<? extends Throwable>> result = new HashMap<>();
174+
for (Map.Entry<String, ResourceExceptionMapper<? extends Throwable>> entry : mappers.entrySet()) {
175+
if (!disabledMappers.contains(entry.getValue().getClassName())) {
176+
result.put(entry.getKey(), entry.getValue());
177+
}
178+
}
150179
return result;
151180
}
152181

0 commit comments

Comments
 (0)