From fb2942691020d46a66c4d41b9617692aad13c468 Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Mon, 9 Sep 2024 13:47:30 +0300 Subject: [PATCH 01/13] fix: obselete name in integration tests pom.xml of quarkus extension (cherry picked from commit f89b9c54e0b89d9f377ec818a7742aee82cd17ff) --- .../integration-tests/java/integration-tests/pom.tpl.qute.xml | 2 +- .../quarkus-my-quarkiverse-ext_integration-tests_pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/integration-tests/java/integration-tests/pom.tpl.qute.xml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/integration-tests/java/integration-tests/pom.tpl.qute.xml index 6f75152063220..03e98f152206a 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/integration-tests/java/integration-tests/pom.tpl.qute.xml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/integration-tests/java/integration-tests/pom.tpl.qute.xml @@ -25,7 +25,7 @@ io.quarkus - quarkus-resteasy-reactive + quarkus-rest {group-id} diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_integration-tests_pom.xml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_integration-tests_pom.xml index fee0d49c79ac2..d9f77b21dfc98 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_integration-tests_pom.xml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_integration-tests_pom.xml @@ -17,7 +17,7 @@ io.quarkus - quarkus-resteasy-reactive + quarkus-rest io.quarkiverse.my-quarkiverse-ext From 7bf93398a4baca024231d6c83be173275d8933f2 Mon Sep 17 00:00:00 2001 From: brunobat Date: Mon, 9 Sep 2024 14:33:53 +0100 Subject: [PATCH 02/13] Fix flacky tests (cherry picked from commit 9799655bdb42cf0119a23e7f9b54ee6eb974fe8c) --- .../reactive/OpenTelemetryReactiveTest.java | 11 +++++++++-- .../io/quarkus/it/opentelemetry/spi/OTelSpiTest.java | 11 ++++++++--- .../it/opentelemetry/OpenTelemetryInjectionsTest.java | 11 +++++++++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java index 757e4455e200e..6ec053fa440cc 100644 --- a/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java +++ b/integration-tests/opentelemetry-reactive/src/test/java/io/quarkus/it/opentelemetry/reactive/OpenTelemetryReactiveTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Duration; import java.util.List; import java.util.Map; import java.util.Optional; @@ -41,8 +42,14 @@ public class OpenTelemetryReactiveTest { @BeforeEach @AfterEach void reset() { - given().get("/reset").then().statusCode(HTTP_OK); - await().atMost(5, SECONDS).until(() -> getSpans().size() == 0); + await().atMost(Duration.ofSeconds(30L)).until(() -> { + // make sure spans are cleared + List> spans = getSpans(); + if (!spans.isEmpty()) { + given().get("/reset").then().statusCode(HTTP_OK); + } + return spans.isEmpty(); + }); } @Test diff --git a/integration-tests/opentelemetry-spi/src/test/java/io/quarkus/it/opentelemetry/spi/OTelSpiTest.java b/integration-tests/opentelemetry-spi/src/test/java/io/quarkus/it/opentelemetry/spi/OTelSpiTest.java index 94e7cb3fd6428..8148595632a0f 100644 --- a/integration-tests/opentelemetry-spi/src/test/java/io/quarkus/it/opentelemetry/spi/OTelSpiTest.java +++ b/integration-tests/opentelemetry-spi/src/test/java/io/quarkus/it/opentelemetry/spi/OTelSpiTest.java @@ -4,7 +4,6 @@ import static io.restassured.RestAssured.get; import static io.restassured.RestAssured.given; import static java.net.HttpURLConnection.HTTP_OK; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.jupiter.api.Assertions.*; @@ -33,8 +32,14 @@ public class OTelSpiTest { @BeforeEach @AfterEach void reset() { - given().get("/reset").then().statusCode(HTTP_OK); - await().atMost(5, SECONDS).until(() -> getSpans().size() == 0); + await().atMost(Duration.ofSeconds(30L)).until(() -> { + // make sure spans are cleared + List> spans = getSpans(); + if (!spans.isEmpty()) { + given().get("/reset").then().statusCode(HTTP_OK); + } + return spans.isEmpty(); + }); } private List> getSpans() { diff --git a/integration-tests/opentelemetry/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryInjectionsTest.java b/integration-tests/opentelemetry/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryInjectionsTest.java index 9430bd7583a3c..b945bbddf22ef 100644 --- a/integration-tests/opentelemetry/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryInjectionsTest.java +++ b/integration-tests/opentelemetry/src/test/java/io/quarkus/it/opentelemetry/OpenTelemetryInjectionsTest.java @@ -6,6 +6,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; +import java.time.Duration; import java.util.List; import java.util.Map; @@ -22,8 +23,14 @@ public class OpenTelemetryInjectionsTest { @BeforeEach @AfterEach void reset() { - given().get("/reset").then().statusCode(HTTP_OK); - await().atMost(5, SECONDS).until(() -> getSpans().size() == 0); + await().atMost(Duration.ofSeconds(30L)).until(() -> { + // make sure spans are cleared + List> spans = getSpans(); + if (!spans.isEmpty()) { + given().get("/reset").then().statusCode(HTTP_OK); + } + return spans.isEmpty(); + }); } private List> getSpans() { From 18ae4d2e88d37895c7bbbf018f9960bf614691c3 Mon Sep 17 00:00:00 2001 From: Matheus Cruz Date: Sat, 7 Sep 2024 11:22:12 -0300 Subject: [PATCH 03/13] Use local svg instead from simpleicons.org The vscode icon was removed so let's be safe and host them on our side. (cherry picked from commit a9e375523c388650ac09f12c54f6c8a371fd1778) --- docs/src/main/asciidoc/ide-tooling.adoc | 8 ++++---- docs/src/main/asciidoc/images/eclipseche.svg | 1 + docs/src/main/asciidoc/images/eclipseide.svg | 1 + docs/src/main/asciidoc/images/intellijidea.svg | 1 + docs/src/main/asciidoc/images/visualstudiocode.svg | 4 ++++ 5 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 docs/src/main/asciidoc/images/eclipseche.svg create mode 100644 docs/src/main/asciidoc/images/eclipseide.svg create mode 100644 docs/src/main/asciidoc/images/intellijidea.svg create mode 100644 docs/src/main/asciidoc/images/visualstudiocode.svg diff --git a/docs/src/main/asciidoc/ide-tooling.adoc b/docs/src/main/asciidoc/ide-tooling.adoc index d9531c39808de..f7b1f1dae9e29 100644 --- a/docs/src/main/asciidoc/ide-tooling.adoc +++ b/docs/src/main/asciidoc/ide-tooling.adoc @@ -22,10 +22,10 @@ In addition, IntelliJ IDEA has additional support for Quarkus in their Ultimate The table below gives an overview of the current IDEs with links and a high-level overview of their features. -:vscode-logo: https://simpleicons.org/icons/visualstudiocode.svg -:eclipse-logo: https://simpleicons.org/icons/eclipseide.svg -:intellij-logo: https://simpleicons.org/icons/intellijidea.svg -:che-logo: https://simpleicons.org/icons/eclipseche.svg +:vscode-logo: visualstudiocode.svg +:eclipse-logo: eclipseide.svg +:intellij-logo: intellijidea.svg +:che-logo: eclipseche.svg [cols="6*^", header] |=== | . diff --git a/docs/src/main/asciidoc/images/eclipseche.svg b/docs/src/main/asciidoc/images/eclipseche.svg new file mode 100644 index 0000000000000..904aff3755a4a --- /dev/null +++ b/docs/src/main/asciidoc/images/eclipseche.svg @@ -0,0 +1 @@ +Eclipse Che \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/eclipseide.svg b/docs/src/main/asciidoc/images/eclipseide.svg new file mode 100644 index 0000000000000..80a9282e05c84 --- /dev/null +++ b/docs/src/main/asciidoc/images/eclipseide.svg @@ -0,0 +1 @@ +Eclipse IDE \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/intellijidea.svg b/docs/src/main/asciidoc/images/intellijidea.svg new file mode 100644 index 0000000000000..6cc5f0f214ddb --- /dev/null +++ b/docs/src/main/asciidoc/images/intellijidea.svg @@ -0,0 +1 @@ +IntelliJ IDEA \ No newline at end of file diff --git a/docs/src/main/asciidoc/images/visualstudiocode.svg b/docs/src/main/asciidoc/images/visualstudiocode.svg new file mode 100644 index 0000000000000..cb4cb1501cc30 --- /dev/null +++ b/docs/src/main/asciidoc/images/visualstudiocode.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From b0cd94cce8daf2a1e272c7d0a47c962cfb1275d3 Mon Sep 17 00:00:00 2001 From: AxiomaticFixedChimpanzee <179703613+AxiomaticFixedChimpanzee@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:08:49 +0200 Subject: [PATCH 04/13] Update rest-data-panache docs to clarify experimental status The Panache extension for generating CRUD resources is split into 3 packages, the most-used one of which is stable. But readers of the guide are greeted with a warning claiming the feature is experimental, which is driving teams away from using it. This patch removes the warning and clarifies in the compatibility table the status of each package, as per https://quarkus.io/extensions/?search-regex=panache&status=stable (cherry picked from commit 3ac37f8504a215e97d46ca6d1bc5f9f6e6b23f0d) --- docs/src/main/asciidoc/rest-data-panache.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/rest-data-panache.adoc b/docs/src/main/asciidoc/rest-data-panache.adoc index ff002dbb2db72..ac5c22cc5becb 100644 --- a/docs/src/main/asciidoc/rest-data-panache.adoc +++ b/docs/src/main/asciidoc/rest-data-panache.adoc @@ -13,7 +13,6 @@ include::_attributes.adoc[] A lot of web applications are monotonous CRUD applications with REST APIs that are tedious to write. To streamline this task, REST Data with Panache extension can generate the basic CRUD endpoints for your entities and repositories. -While this extension is still experimental and provides a limited feature set, we hope to get an early feedback for it. Currently, this extension supports Hibernate ORM and MongoDB with Panache and can generate CRUD resources that work with `application/json` and `application/hal+json` content. == Setting up REST Data with Panache @@ -23,17 +22,20 @@ Please, check out the next compatibility table to use the right one according to .Compatibility Table |=== -|Extension |Hibernate | RESTEasy +|Extension |Status |Hibernate |RESTEasy |<> +|`Stable` |`ORM` |`Classic and Reactive` |<> +|`Experimental` |`Reactive` |`Reactive` |<> +|`Experimental` |`ORM` |`Classic and Reactive` |=== From 612226c86dc586fa21c893ab05fe980cda009233 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 5 Sep 2024 12:11:10 +0300 Subject: [PATCH 05/13] Embed quarkus version in native executable as a global string symbol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables getting the quarkus version without running the native executable: ``` ❯ strings target/quarkus-999-SNAPSHOT-runner | grep -F '__quarkus_analytics__quarkus.version' quarkus.version=999-SNAPSHOT ``` Closes https://github.com/quarkusio/quarkus/issues/43020 (cherry picked from commit 65c7e68b9e594378081b6376cda63dd1c301370e) --- .../nativeimage/ReflectiveFieldBuildItem.java | 12 +++++++----- .../deployment/steps/MainClassBuildStep.java | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java index 28ae2f07a6b94..ecfdfd7e491b3 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/ReflectiveFieldBuildItem.java @@ -13,9 +13,7 @@ public final class ReflectiveFieldBuildItem extends MultiBuildItem { final String reason; public ReflectiveFieldBuildItem(String reason, FieldInfo field) { - this.reason = reason; - this.name = field.name(); - this.declaringClass = field.declaringClass().name().toString(); + this(reason, field.declaringClass().name().toString(), field.name()); } public ReflectiveFieldBuildItem(FieldInfo field) { @@ -27,9 +25,13 @@ public ReflectiveFieldBuildItem(Field field) { } public ReflectiveFieldBuildItem(String reason, Field field) { + this(reason, field.getDeclaringClass().getName(), field.getName()); + } + + public ReflectiveFieldBuildItem(String reason, String declaringClass, String fieldName) { this.reason = reason; - this.name = field.getName(); - this.declaringClass = field.getDeclaringClass().getName(); + this.name = fieldName; + this.declaringClass = declaringClass; } public String getDeclaringClass() { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java index ecdacc7f44616..9b5a17a380853 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java @@ -57,6 +57,7 @@ import io.quarkus.deployment.builditem.StaticBytecodeRecorderBuildItem; import io.quarkus.deployment.builditem.SystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem; import io.quarkus.deployment.configuration.RunTimeConfigurationGenerator; import io.quarkus.deployment.naming.NamingConfig; import io.quarkus.deployment.pkg.PackageConfig; @@ -96,6 +97,9 @@ public class MainClassBuildStep { static final String STARTUP_CONTEXT = "STARTUP_CONTEXT"; static final String LOG = "LOG"; static final String JAVA_LIBRARY_PATH = "java.library.path"; + // This is declared as a constant so that it can be grepped for in the native-image binary using `strings`, e.g.: + // strings ./target/quarkus-runner | grep "__quarkus_analytics__quarkus.version=" + public static final String QUARKUS_ANALYTICS_QUARKUS_VERSION = "__QUARKUS_ANALYTICS_QUARKUS_VERSION"; public static final String GENERATE_APP_CDS_SYSTEM_PROPERTY = "quarkus.appcds.generate"; @@ -155,6 +159,9 @@ void build(List staticInitTasks, FieldCreator scField = file.getFieldCreator(STARTUP_CONTEXT_FIELD); scField.setModifiers(Modifier.PUBLIC | Modifier.STATIC); + FieldCreator quarkusVersionField = file.getFieldCreator(QUARKUS_ANALYTICS_QUARKUS_VERSION, String.class) + .setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL); + MethodCreator ctor = file.getMethodCreator("", void.class); ctor.invokeSpecialMethod(ofMethod(Application.class, "", void.class, boolean.class), ctor.getThis(), ctor.load(launchMode.isAuxiliaryApplication())); @@ -192,6 +199,10 @@ void build(List staticInitTasks, mv.writeStaticField(logField.getFieldDescriptor(), mv.invokeStaticMethod( ofMethod(Logger.class, "getLogger", Logger.class, String.class), mv.load("io.quarkus.application"))); + // Init the __QUARKUS_ANALYTICS_QUARKUS_VERSION field + mv.writeStaticField(quarkusVersionField.getFieldDescriptor(), + mv.load("__quarkus_analytics__quarkus.version=" + Version.getVersion())); + ResultHandle startupContext = mv.newInstance(ofConstructor(StartupContext.class)); mv.writeStaticField(scField.getFieldDescriptor(), startupContext); TryBlock tryBlock = mv.tryBlock(); @@ -703,4 +714,10 @@ private static Result invalid() { } } + @BuildStep + ReflectiveFieldBuildItem setupVersionField() { + return new ReflectiveFieldBuildItem( + "Ensure it's included in the executable to be able to grep the quarkus version", + Application.APP_CLASS_NAME, QUARKUS_ANALYTICS_QUARKUS_VERSION); + } } From eb321a831254ebbbea657ca8691ed9c8120ee7ac Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 9 Sep 2024 11:43:08 +0300 Subject: [PATCH 06/13] Allows users to exclude DefaultMismatchedInputException A few users have run into an issue where they are trying to handle all Jackson exceptions but the existence of DefaultMismatchedInputException prevents that for MismatchedInputException (as per JAX-RS / Jakarta REST rules). This change allows users to do use: quarkus.class-loading.removed-resources."io.quarkus\:quarkus-rest-jackson"=io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.class in order to have Quarkus ignore the mapper. (cherry picked from commit 7f09b8c0289c6a915d417a7a7a7e594b319a9b19) --- .../ResteasyReactiveJacksonProcessor.java | 15 ++++-- ...dedBuiltInAndIncludedCustomMapperTest.java | 46 +++++++++++++++++++ .../DefaultMismatchedInputException.java | 1 + 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java index 386200105bd09..0e1ce2874bf03 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java @@ -71,7 +71,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; @@ -110,6 +109,7 @@ public class ResteasyReactiveJacksonProcessor { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final List 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.DefaultMismatchedInputException"; @BuildStep void feature(BuildProducer feature) { @@ -132,9 +132,16 @@ ReinitializeVertxJsonBuildItem vertxJson() { } @BuildStep - ExceptionMapperBuildItem exceptionMappers() { - return new ExceptionMapperBuildItem(DefaultMismatchedInputException.class.getName(), - MismatchedInputException.class.getName(), Priorities.USER + 100, false); + void exceptionMappers(BuildProducer 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 diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java new file mode 100644 index 0000000000000..e0ca92a987963 --- /dev/null +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java @@ -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/DefaultMismatchedInputException.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 { + + @Override + public Response toResponse(DatabindException exception) { + return Response.status(999).build(); + } + } +} diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java index 54783b513b961..151ab715d69c4 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java @@ -10,6 +10,7 @@ import io.quarkus.runtime.LaunchMode; +@SuppressWarnings("unused") public class DefaultMismatchedInputException implements ExceptionMapper { From a1d175f92cb809457093e3d185615cef73852caf Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 9 Sep 2024 11:51:39 +0300 Subject: [PATCH 07/13] Document how to turn off DefaultMismatchedInputException (cherry picked from commit 7a898637e123e4fb8c4c0dc2e715d746c58dfe97) --- docs/src/main/asciidoc/rest.adoc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/rest.adoc b/docs/src/main/asciidoc/rest.adoc index e38650b354d85..8d08c91c1fee5 100644 --- a/docs/src/main/asciidoc/rest.adoc +++ b/docs/src/main/asciidoc/rest.adoc @@ -1391,9 +1391,28 @@ In both cases, importing those modules will allow HTTP message bodies to be read and serialised to JSON, for <>. -==== 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 + +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. +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/DefaultMismatchedInputException.class +---- + +which essentially makes Quarkus ignore the `ExceptionMapper` for `MismatchedInputException` completely. +==== [[secure-serialization]] ===== Secure serialization From 17a508d7235ca01aca77e0a5c259dd216f6f588c Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 10 Sep 2024 14:46:14 +0300 Subject: [PATCH 08/13] Rename DefaultMismatchedInputException to BuiltinMismatchedInputExceptionMapper (cherry picked from commit e9cddc0508f5c1c520bf448da66ecd65500de908) --- docs/src/main/asciidoc/rest.adoc | 2 +- .../deployment/processor/ResteasyReactiveJacksonProcessor.java | 2 +- ...nInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java | 2 +- ...xception.java => BuiltinMismatchedInputExceptionMapper.java} | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/{DefaultMismatchedInputException.java => BuiltinMismatchedInputExceptionMapper.java} (98%) diff --git a/docs/src/main/asciidoc/rest.adoc b/docs/src/main/asciidoc/rest.adoc index 8d08c91c1fee5..81aca81ff5ad4 100644 --- a/docs/src/main/asciidoc/rest.adoc +++ b/docs/src/main/asciidoc/rest.adoc @@ -1408,7 +1408,7 @@ 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/DefaultMismatchedInputException.class +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. diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java index 0e1ce2874bf03..3d37398a9be5f 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java @@ -109,7 +109,7 @@ public class ResteasyReactiveJacksonProcessor { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final List 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.DefaultMismatchedInputException"; + public static final String DEFAULT_MISMATCHED_INPUT_EXCEPTION = "io.quarkus.resteasy.reactive.jackson.runtime.mappers.BuiltinMismatchedInputExceptionMapper"; @BuildStep void feature(BuildProducer feature) { diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java index e0ca92a987963..e334002585c07 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/ExceptionInReaderWithExcludedBuiltInAndIncludedCustomMapperTest.java @@ -27,7 +27,7 @@ public JavaArchive get() { .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/DefaultMismatchedInputException.class"); + "io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.class"); @Test public void test() { diff --git a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.java similarity index 98% rename from extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java rename to extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.java index 151ab715d69c4..e9fe48c834fca 100644 --- a/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/DefaultMismatchedInputException.java +++ b/extensions/resteasy-reactive/rest-jackson/runtime/src/main/java/io/quarkus/resteasy/reactive/jackson/runtime/mappers/BuiltinMismatchedInputExceptionMapper.java @@ -11,7 +11,7 @@ import io.quarkus.runtime.LaunchMode; @SuppressWarnings("unused") -public class DefaultMismatchedInputException +public class BuiltinMismatchedInputExceptionMapper implements ExceptionMapper { @Override From 6789f0297fc6b163a1222074c72bdd77472740bb Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Mon, 9 Sep 2024 19:25:59 +0100 Subject: [PATCH 09/13] Add runtime properties to Quarkus builder (cherry picked from commit be4817d541882225767e9e3655ec5bf325045360) --- .../io/quarkus/deployment/CodeGenerator.java | 6 ++++-- .../quarkus/deployment/ExtensionLoader.java | 6 ++++-- .../quarkus/deployment/QuarkusAugmentor.java | 18 ++++++++++++----- .../BuildTimeConfigurationReader.java | 20 +++++++++---------- .../deployment/jbang/JBangAugmentorImpl.java | 1 + .../io/quarkus/launcher/JBangIntegration.java | 9 +++++++-- .../bootstrap/app/QuarkusBootstrap.java | 13 ++++++++++++ .../bootstrap/jbang/JBangBuilderImpl.java | 9 ++++++++- 8 files changed, 60 insertions(+), 22 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java b/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java index 36dae8b38f8f3..b0d2945ea5f43 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/CodeGenerator.java @@ -227,7 +227,8 @@ public static void dumpCurrentConfigValues(ApplicationModel appModel, String lau if (previouslyRecordedProperties.isEmpty()) { try { readConfig(appModel, mode, buildSystemProps, deploymentClassLoader, configReader -> { - var config = configReader.initConfiguration(mode, buildSystemProps, appModel.getPlatformProperties()); + var config = configReader.initConfiguration(mode, buildSystemProps, new Properties(), + appModel.getPlatformProperties()); final Map allProps = new HashMap<>(); for (String name : config.getPropertyNames()) { allProps.put(name, ConfigTrackingValueTransformer.asString(config.getConfigValue(name))); @@ -287,7 +288,8 @@ public static void dumpCurrentConfigValues(ApplicationModel appModel, String lau public static Config getConfig(ApplicationModel appModel, LaunchMode launchMode, Properties buildSystemProps, QuarkusClassLoader deploymentClassLoader) throws CodeGenException { return readConfig(appModel, launchMode, buildSystemProps, deploymentClassLoader, - configReader -> configReader.initConfiguration(launchMode, buildSystemProps, appModel.getPlatformProperties())); + configReader -> configReader.initConfiguration(launchMode, buildSystemProps, new Properties(), + appModel.getPlatformProperties())); } public static T readConfig(ApplicationModel appModel, LaunchMode launchMode, Properties buildSystemProps, diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java index 6549aed18394b..6d7bc5bd526c9 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/ExtensionLoader.java @@ -132,12 +132,14 @@ private static boolean isRecorder(AnnotatedElement element) { * @throws IOException if the class loader could not load a resource * @throws ClassNotFoundException if a build step class is not found */ - public static Consumer loadStepsFrom(ClassLoader classLoader, Properties buildSystemProps, + public static Consumer loadStepsFrom(ClassLoader classLoader, + Properties buildSystemProps, Properties runtimeProperties, ApplicationModel appModel, LaunchMode launchMode, DevModeType devModeType) throws IOException, ClassNotFoundException { final BuildTimeConfigurationReader reader = new BuildTimeConfigurationReader(classLoader); - final SmallRyeConfig src = reader.initConfiguration(launchMode, buildSystemProps, appModel.getPlatformProperties()); + final SmallRyeConfig src = reader.initConfiguration(launchMode, buildSystemProps, runtimeProperties, + appModel.getPlatformProperties()); // install globally QuarkusConfigFactory.setConfig(src); final BuildTimeConfigurationReader.ReadResult readResult = reader.readConfiguration(src); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java b/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java index ef13a5eeb0ea8..b423d83378756 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/QuarkusAugmentor.java @@ -55,6 +55,7 @@ public class QuarkusAugmentor { private final Collection excludedFromIndexing; private final LiveReloadBuildItem liveReloadBuildItem; private final Properties buildSystemProperties; + private final Properties runtimeProperties; private final Path targetDir; private final ApplicationModel effectiveModel; private final Supplier depInfoProvider; @@ -75,6 +76,7 @@ public class QuarkusAugmentor { this.excludedFromIndexing = builder.excludedFromIndexing; this.liveReloadBuildItem = builder.liveReloadState; this.buildSystemProperties = builder.buildSystemProperties; + this.runtimeProperties = builder.runtimeProperties; this.targetDir = builder.targetDir; this.effectiveModel = builder.effectiveModel; this.baseName = builder.baseName; @@ -102,13 +104,9 @@ public BuildResult run() throws Exception { final BuildChainBuilder chainBuilder = BuildChain.builder(); chainBuilder.setClassLoader(deploymentClassLoader); - //provideCapabilities(chainBuilder); - - //TODO: we load everything from the deployment class loader - //this allows the deployment config (application.properties) to be loaded, but in theory could result - //in additional stuff from the deployment leaking in, this is unlikely but has a bit of a smell. ExtensionLoader.loadStepsFrom(deploymentClassLoader, buildSystemProperties == null ? new Properties() : buildSystemProperties, + runtimeProperties == null ? new Properties() : runtimeProperties, effectiveModel, launchMode, devModeType) .accept(chainBuilder); @@ -210,6 +208,7 @@ public static final class Builder { LaunchMode launchMode = LaunchMode.NORMAL; LiveReloadBuildItem liveReloadState = new LiveReloadBuildItem(); Properties buildSystemProperties; + Properties runtimeProperties; ApplicationModel effectiveModel; String baseName = QUARKUS_APPLICATION; @@ -322,6 +321,15 @@ public Builder setBuildSystemProperties(final Properties buildSystemProperties) return this; } + public Properties getRuntimeProperties() { + return runtimeProperties; + } + + public Builder setRuntimeProperties(final Properties runtimeProperties) { + this.runtimeProperties = runtimeProperties; + return this; + } + public Builder setRebuild(boolean rebuild) { this.rebuild = rebuild; return this; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java index e42d94cbb07b6..e493211f6336e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java @@ -380,7 +380,7 @@ public List getBuildTimeVisibleMappings() { * @param platformProperties Quarkus platform properties to add as a configuration source * @return configuration instance */ - public SmallRyeConfig initConfiguration(LaunchMode launchMode, Properties buildSystemProps, + public SmallRyeConfig initConfiguration(LaunchMode launchMode, Properties buildSystemProps, Properties runtimeProperties, Map platformProperties) { // now prepare & load the build configuration SmallRyeConfigBuilder builder = ConfigUtils.configBuilder(false, launchMode); @@ -388,17 +388,17 @@ public SmallRyeConfig initConfiguration(LaunchMode launchMode, Properties buildS builder.forClassLoader(classLoader); } - DefaultValuesConfigurationSource ds1 = new DefaultValuesConfigurationSource(getBuildTimePatternMap()); - DefaultValuesConfigurationSource ds2 = new DefaultValuesConfigurationSource(getBuildTimeRunTimePatternMap()); - PropertiesConfigSource pcs = new PropertiesConfigSource(buildSystemProps, "Build system"); - if (platformProperties.isEmpty()) { - builder.withSources(ds1, ds2, pcs); - } else { + builder + .withSources(new DefaultValuesConfigurationSource(getBuildTimePatternMap())) + .withSources(new DefaultValuesConfigurationSource(getBuildTimeRunTimePatternMap())) + .withSources(new PropertiesConfigSource(buildSystemProps, "Build system")) + .withSources(new PropertiesConfigSource(runtimeProperties, "Runtime Properties")); + + if (!platformProperties.isEmpty()) { // Our default value configuration source is using an ordinal of Integer.MIN_VALUE // (see io.quarkus.deployment.configuration.DefaultValuesConfigurationSource) - DefaultValuesConfigSource platformConfigSource = new DefaultValuesConfigSource(platformProperties, - "Quarkus platform", Integer.MIN_VALUE + 1000); - builder.withSources(ds1, ds2, platformConfigSource, pcs); + builder.withSources( + new DefaultValuesConfigSource(platformProperties, "Quarkus platform", Integer.MIN_VALUE + 1000)); } for (ConfigClassWithPrefix mapping : getBuildTimeVisibleMappings()) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java index 4fe1d0469bd19..9d94bcac05481 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java @@ -51,6 +51,7 @@ public void accept(CuratedApplication curatedApplication, Map re .setTargetDir(quarkusBootstrap.getTargetDirectory()) .setDeploymentClassLoader(curatedApplication.createDeploymentClassLoader()) .setBuildSystemProperties(quarkusBootstrap.getBuildSystemProperties()) + .setRuntimeProperties(quarkusBootstrap.getRuntimeProperties()) .setEffectiveModel(curatedApplication.getApplicationModel()); if (quarkusBootstrap.getBaseName() != null) { builder.setBaseName(quarkusBootstrap.getBaseName()); diff --git a/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java b/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java index 7e7cf1fb12cb2..e0adc8e68e543 100644 --- a/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java +++ b/core/launcher/src/main/java/io/quarkus/launcher/JBangIntegration.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import io.quarkus.bootstrap.BootstrapConstants; @@ -46,6 +47,7 @@ public static Map postBuild(Path appClasses, Path pomFile, List< return ret; } + Properties configurationProperties = new Properties(); for (String comment : comments) { //we allow config to be provided via //Q:CONFIG name=value if (comment.startsWith(CONFIG)) { @@ -54,7 +56,7 @@ public static Map postBuild(Path appClasses, Path pomFile, List< if (equals == -1) { throw new RuntimeException("invalid config " + comment); } - System.setProperty(conf.substring(0, equals), conf.substring(equals + 1)); + configurationProperties.setProperty(conf.substring(0, equals), conf.substring(equals + 1)); } } @@ -117,12 +119,15 @@ public Enumeration getResources(String name) throws IOException { Thread.currentThread().setContextClassLoader(loader); Class launcher = loader.loadClass("io.quarkus.bootstrap.jbang.JBangBuilderImpl"); return (Map) launcher - .getDeclaredMethod("postBuild", Path.class, Path.class, List.class, List.class, boolean.class).invoke( + .getDeclaredMethod("postBuild", Path.class, Path.class, List.class, List.class, Properties.class, + boolean.class) + .invoke( null, appClasses, pomFile, repositories, dependencies, + configurationProperties, nativeImage); } catch (Exception e) { throw new RuntimeException(e); diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java index 966629bcc767e..35f44526d7eab 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java @@ -65,6 +65,7 @@ public class QuarkusBootstrap implements Serializable { private final List excludeFromClassPath; private final Properties buildSystemProperties; + private final Properties runtimeProperties; private final String baseName; private final String originalBaseName; private final Path targetDirectory; @@ -100,6 +101,7 @@ private QuarkusBootstrap(Builder builder) { this.excludeFromClassPath = new ArrayList<>(builder.excludeFromClassPath); this.projectRoot = builder.projectRoot != null ? builder.projectRoot.normalize() : null; this.buildSystemProperties = builder.buildSystemProperties != null ? builder.buildSystemProperties : new Properties(); + this.runtimeProperties = builder.runtimeProperties != null ? builder.runtimeProperties : new Properties(); this.mode = builder.mode; this.offline = builder.offline; this.test = builder.test; @@ -202,6 +204,10 @@ public Properties getBuildSystemProperties() { return buildSystemProperties; } + public Properties getRuntimeProperties() { + return runtimeProperties; + } + public Path getProjectRoot() { return projectRoot; } @@ -266,6 +272,7 @@ public Builder clonedBuilder() { .setProjectRoot(projectRoot) .setBaseClassLoader(baseClassLoader) .setBuildSystemProperties(buildSystemProperties) + .setRuntimeProperties(runtimeProperties) .setMode(mode) .setTest(test) .setLocalProjectDiscovery(localProjectDiscovery) @@ -316,6 +323,7 @@ public static class Builder { final List additionalDeploymentArchives = new ArrayList<>(); final List excludeFromClassPath = new ArrayList<>(); Properties buildSystemProperties; + Properties runtimeProperties; Mode mode = Mode.PROD; Boolean offline; boolean test; @@ -389,6 +397,11 @@ public Builder setBuildSystemProperties(Properties buildSystemProperties) { return this; } + public Builder setRuntimeProperties(Properties runtimeProperties) { + this.runtimeProperties = runtimeProperties; + return this; + } + public Builder setOffline(boolean offline) { this.offline = offline; return this; diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/jbang/JBangBuilderImpl.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/jbang/JBangBuilderImpl.java index 4b5c60c0bdd93..26fb7f706b243 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/jbang/JBangBuilderImpl.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/jbang/JBangBuilderImpl.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.stream.Collectors; import org.eclipse.aether.repository.RemoteRepository; @@ -26,8 +27,12 @@ import io.quarkus.maven.dependency.ResolvedArtifactDependency; public class JBangBuilderImpl { - public static Map postBuild(Path appClasses, Path pomFile, List> repositories, + public static Map postBuild( + Path appClasses, + Path pomFile, + List> repositories, List> dependencies, + Properties configurationProperties, boolean nativeImage) { final MavenArtifactResolver quarkusResolver; try { @@ -80,6 +85,8 @@ public static Map postBuild(Path appClasses, Path pomFile, List< }).collect(Collectors.toList())) .setAppArtifact(appArtifact) .setIsolateDeployment(true) + .setBuildSystemProperties(configurationProperties) + .setRuntimeProperties(configurationProperties) .setMode(QuarkusBootstrap.Mode.PROD); CuratedApplication app = builder From e557f13e4f37570c34ec48da46c12a840e4af221 Mon Sep 17 00:00:00 2001 From: KERN Christian Date: Tue, 10 Sep 2024 13:19:43 +0200 Subject: [PATCH 10/13] Fixes #42908 (cherry picked from commit 0580edf1cc4ea4cb61f017ccf44dcdbc3b583d90) --- .../dev/filesystem/QuarkusFileManager.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java index 4ac5314804078..7852c0370f0a7 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java @@ -22,6 +22,8 @@ protected QuarkusFileManager(StandardJavaFileManager fileManager, Context contex this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, List.of(context.getGeneratedSourcesDirectory())); } if (context.getAnnotationProcessorPaths() != null) { + // Paths might be missing! (see: https://github.com/quarkusio/quarkus/issues/42908) + ensureDirectories(context.getAnnotationProcessorPaths()); this.fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, context.getAnnotationProcessorPaths()); } } catch (IOException e) { @@ -39,12 +41,22 @@ public void reset(Context context) { this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, List.of(context.getGeneratedSourcesDirectory())); } if (context.getAnnotationProcessorPaths() != null) { + // Paths might be missing! (see: https://github.com/quarkusio/quarkus/issues/42908) + ensureDirectories(context.getAnnotationProcessorPaths()); this.fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, context.getAnnotationProcessorPaths()); } } catch (IOException e) { throw new RuntimeException("Cannot reset file manager", e); } } + + private void ensureDirectories(Iterable directories){ + for (File processorPath : directories) { + if (!processorPath.exists()) { + processorPath.mkdirs(); + } + } + } @Override public void close() throws IOException { From 2bb7dba5f17ef805275ee7ff1ed53955eba84eb3 Mon Sep 17 00:00:00 2001 From: KERN Christian Date: Tue, 10 Sep 2024 15:56:38 +0200 Subject: [PATCH 11/13] Added Runtime exception on failing directory creation (cherry picked from commit dd8ae2cf88ec16075be9b967f2ae73596a6bc9e0) --- .../dev/filesystem/QuarkusFileManager.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java index 7852c0370f0a7..71bd65e54830d 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/filesystem/QuarkusFileManager.java @@ -49,11 +49,14 @@ public void reset(Context context) { throw new RuntimeException("Cannot reset file manager", e); } } - - private void ensureDirectories(Iterable directories){ - for (File processorPath : directories) { - if (!processorPath.exists()) { - processorPath.mkdirs(); + + private void ensureDirectories(Iterable directories) { + for (File directory : directories) { + if (!directory.exists()) { + final boolean success = directory.mkdirs(); + if (!success) { + throw new RuntimeException("Cannot create directory " + directory); + } } } } From 48c2de96ca77876021b2b9eaebf65dea8af212c3 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 10 Sep 2024 22:12:14 +0200 Subject: [PATCH 12/13] Fix javadoc for quarkus.bootstrap.incubating-model-resolver Noticed while working on the config doc. (cherry picked from commit bd23c2d3b096d75dec808b4f12ee804c8de87e64) --- .../src/main/java/io/quarkus/deployment/BootstrapConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java index fc4e1e776034c..6c456cd795baf 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/BootstrapConfig.java @@ -42,7 +42,7 @@ public class BootstrapConfig { boolean disableJarCache; /** - * A temporary option introduced to avoid a logging warning when {@code }-Dquarkus.bootstrap.incubating-model-resolver} + * A temporary option introduced to avoid a logging warning when {@code -Dquarkus.bootstrap.incubating-model-resolver} * is added to the build command line. * This option enables an incubating implementation of the Quarkus Application Model resolver. * This option will be removed as soon as the incubating implementation becomes the default one. From db0dfde23ceac11d3fba065ef17c84099d6ed9d1 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 10 Sep 2024 22:33:17 +0200 Subject: [PATCH 13/13] Config Doc - Reset list status for passthrough maps (cherry picked from commit 34c67b0d1cc6a138e9513988fc90b3e29069f661) --- .../processor/documentation/config/discovery/ResolvedType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ResolvedType.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ResolvedType.java index 01d845e500a40..c2a3b9bf223d0 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ResolvedType.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ResolvedType.java @@ -70,7 +70,7 @@ public static ResolvedType makeMap(TypeMirror type, ResolvedType unwrappedResolv return new ResolvedType(type, unwrappedResolvedType.unwrappedType, unwrappedResolvedType.binaryName, unwrappedResolvedType.qualifiedName, unwrappedResolvedType.simplifiedName, unwrappedResolvedType.isPrimitive, - true, unwrappedResolvedType.isList, + true, false, unwrappedResolvedType.isOptional, unwrappedResolvedType.isDeclared, unwrappedResolvedType.isInterface, unwrappedResolvedType.isClass, unwrappedResolvedType.isEnum, unwrappedResolvedType.isDuration, unwrappedResolvedType.isConfigGroup);