Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows users to exclude DefaultMismatchedInputException #43126

Merged
merged 3 commits into from
Sep 10, 2024
Merged
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
23 changes: 21 additions & 2 deletions docs/src/main/asciidoc/rest.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1415,9 +1415,28 @@
and serialised to JSON, for <<resource-types,all the types not already registered with a more specific
serialisation>>.

==== Advanced Jackson-specific features
==== Jackson-specific features

When using the `quarkus-rest-jackson` extension there are some advanced features that Quarkus REST supports.
===== Exception handling

Check warning on line 1420 in docs/src/main/asciidoc/rest.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.SentenceLength] Try to keep sentences to an average of 32 words or fewer. Raw Output: {"message": "[Quarkus.SentenceLength] Try to keep sentences to an average of 32 words or fewer.", "location": {"path": "docs/src/main/asciidoc/rest.adoc", "range": {"start": {"line": 1420, "column": 16}}}, "severity": "INFO"}

By default, Quarkus provides a built-in `ExceptionMapper` for `MismatchedInputException` which returns an HTTP 400 status code
along with a good error message in Dev and Test modes, about what went wrong during serialization of an entity.

[NOTE]
====
There are situations where various Jackson related exceptions need to handled in a uniform way.For example, the application may need to handle all `JsonMappingException` the same way.

Check warning on line 1427 in docs/src/main/asciidoc/rest.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/rest.adoc", "range": {"start": {"line": 1427, "column": 52}}}, "severity": "INFO"}

Check failure on line 1427 in docs/src/main/asciidoc/rest.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Spacing] Keep one space between words in 'y.F'. Raw Output: {"message": "[Quarkus.Spacing] Keep one space between words in 'y.F'.", "location": {"path": "docs/src/main/asciidoc/rest.adoc", "range": {"start": {"line": 1427, "column": 94}}}, "severity": "ERROR"}

Check warning on line 1427 in docs/src/main/asciidoc/rest.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/rest.adoc", "range": {"start": {"line": 1427, "column": 118}}}, "severity": "INFO"}

Check warning on line 1427 in docs/src/main/asciidoc/rest.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'might (for possibility)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'might (for possibility)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/rest.adoc", "range": {"start": {"line": 1427, "column": 125}}}, "severity": "WARNING"}
This becomes a problem when taking JAX-RS / Jakarta REST rules into account, because the exception mapper `ExceptionMapper` for `MismatchedInputException` would be used instead of the user provide
`ExceptionMapper` for `JsonMappingException` (as `MismatchedInputException` is a subtype of `JsonMappingException`).

One solution for this case is to configure the following:

[source,properties]
----
quarkus.class-loading.removed-resources."io.quarkus\:quarkus-rest-jackson"=io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.class
----

which essentially makes Quarkus ignore the `ExceptionMapper` for `MismatchedInputException` completely.
====

[[secure-serialization]]
===== Secure serialization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
import io.quarkus.resteasy.reactive.jackson.EnableSecureSerialization;
import io.quarkus.resteasy.reactive.jackson.SecureField;
import io.quarkus.resteasy.reactive.jackson.runtime.ResteasyReactiveServerJacksonRecorder;
import io.quarkus.resteasy.reactive.jackson.runtime.mappers.DefaultMismatchedInputException;
import io.quarkus.resteasy.reactive.jackson.runtime.mappers.NativeInvalidDefinitionExceptionMapper;
import io.quarkus.resteasy.reactive.jackson.runtime.security.RolesAllowedConfigExpStorage;
import io.quarkus.resteasy.reactive.jackson.runtime.security.SecurityCustomSerialization;
Expand Down Expand Up @@ -108,6 +107,7 @@ public class ResteasyReactiveJacksonProcessor {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final List<String> HANDLED_MEDIA_TYPES = List.of(MediaType.APPLICATION_JSON, APPLICATION_NDJSON,
APPLICATION_STREAM_JSON);
public static final String DEFAULT_MISMATCHED_INPUT_EXCEPTION = "io.quarkus.resteasy.reactive.jackson.runtime.mappers.BuiltinMismatchedInputExceptionMapper";

@BuildStep
void feature(BuildProducer<FeatureBuildItem> feature) {
Expand All @@ -130,9 +130,16 @@ ReinitializeVertxJsonBuildItem vertxJson() {
}

@BuildStep
ExceptionMapperBuildItem exceptionMappers() {
return new ExceptionMapperBuildItem(DefaultMismatchedInputException.class.getName(),
MismatchedInputException.class.getName(), Priorities.USER + 100, false);
void exceptionMappers(BuildProducer<ExceptionMapperBuildItem> producer) {
try {
Thread.currentThread().getContextClassLoader().loadClass(DEFAULT_MISMATCHED_INPUT_EXCEPTION);
} catch (NoClassDefFoundError | ClassNotFoundException e) {
// the class is not available, likely due to quarkus.class-loading.removed-resources."io.quarkus\:quarkus-rest-jackson"=io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.class
return;
}

producer.produce(new ExceptionMapperBuildItem(DEFAULT_MISMATCHED_INPUT_EXCEPTION,
MismatchedInputException.class.getName(), Priorities.USER + 100, false));
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test;

import java.util.function.Supplier;

import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import com.fasterxml.jackson.databind.DatabindException;

import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest {

@RegisterExtension
static QuarkusUnitTest test = new QuarkusUnitTest()
.setArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(FroMage.class, FroMageEndpoint.class, DatabindExceptionMapper.class);
}
}).overrideConfigKey("quarkus.class-loading.removed-resources.\"io.quarkus\\:quarkus-rest-jackson\"",
"io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.class");

@Test
public void test() {
RestAssured.with().contentType("application/json").body("{\"name\": \"brie\"}").put("/fromage")
.then().statusCode(999);
}

@Provider
public static class DatabindExceptionMapper implements ExceptionMapper<DatabindException> {

@Override
public Response toResponse(DatabindException exception) {
return Response.status(999).build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

import io.quarkus.runtime.LaunchMode;

public class DefaultMismatchedInputException
@SuppressWarnings("unused")
public class BuiltinMismatchedInputExceptionMapper
implements ExceptionMapper<com.fasterxml.jackson.databind.exc.MismatchedInputException> {

@Override
Expand Down
Loading