From 017e57b0bf3eada9bd2e0f12cee777d237347448 Mon Sep 17 00:00:00 2001 From: Maciej Lisowski Date: Tue, 5 Dec 2023 21:18:56 +0100 Subject: [PATCH] Fix io.smallrye.config.ConfigValidationException not being handled properly at Quarkus startup --- .../steps/RuntimeConfigSetupBuildStep.java | 15 ++++++++-- .../runtime/ApplicationLifecycleManager.java | 3 +- .../quarkus/runtime/util/ExceptionUtil.java | 11 +++++++ .../runtime/util/ExceptionUtilTest.java | 29 +++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/RuntimeConfigSetupBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/RuntimeConfigSetupBuildStep.java index ef5fcb0467473..ee549589ec1a1 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/RuntimeConfigSetupBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/RuntimeConfigSetupBuildStep.java @@ -10,11 +10,14 @@ import io.quarkus.deployment.builditem.GeneratedClassBuildItem; import io.quarkus.deployment.builditem.MainBytecodeRecorderBuildItem; import io.quarkus.deployment.builditem.RuntimeConfigSetupCompleteBuildItem; +import io.quarkus.gizmo.CatchBlockCreator; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.ClassOutput; import io.quarkus.gizmo.MethodCreator; +import io.quarkus.gizmo.TryBlock; import io.quarkus.runtime.StartupContext; import io.quarkus.runtime.StartupTask; +import io.quarkus.runtime.configuration.ConfigurationException; public class RuntimeConfigSetupBuildStep { private static final String RUNTIME_CONFIG_STARTUP_TASK_CLASS_NAME = "io.quarkus.deployment.steps.RuntimeConfigSetup"; @@ -37,11 +40,17 @@ void setupRuntimeConfig( .interfaces(StartupTask.class).build()) { try (MethodCreator method = clazz.getMethodCreator("deploy", void.class, StartupContext.class)) { - method.invokeVirtualMethod(ofMethod(StartupContext.class, "setCurrentBuildStepName", void.class, String.class), + TryBlock tryBlock = method.tryBlock(); + tryBlock.invokeVirtualMethod( + ofMethod(StartupContext.class, "setCurrentBuildStepName", void.class, String.class), method.getMethodParam(0), method.load("RuntimeConfigSetupBuildStep.setupRuntimeConfig")); - method.invokeStaticMethod(C_CREATE_RUN_TIME_CONFIG); - method.returnValue(null); + tryBlock.invokeStaticMethod(C_CREATE_RUN_TIME_CONFIG); + tryBlock.returnValue(null); + + CatchBlockCreator cb = tryBlock.addCatch(RuntimeException.class); + cb.throwException(ConfigurationException.class, "Failed to read configuration properties", + cb.getCaughtException()); } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/ApplicationLifecycleManager.java b/core/runtime/src/main/java/io/quarkus/runtime/ApplicationLifecycleManager.java index 48de9f8cf6cfd..4c7ed149e1737 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/ApplicationLifecycleManager.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/ApplicationLifecycleManager.java @@ -187,8 +187,9 @@ public static void run(Application application, Class'."); } - } else if (rootCause instanceof ConfigurationException) { + } else if (ExceptionUtil.isAnyCauseInstanceOf(e, ConfigurationException.class)) { System.err.println(rootCause.getMessage()); + e.printStackTrace(); } else if (rootCause instanceof PreventFurtherStepsException && !StringUtil.isNullOrEmpty(rootCause.getMessage())) { System.err.println(rootCause.getMessage()); diff --git a/core/runtime/src/main/java/io/quarkus/runtime/util/ExceptionUtil.java b/core/runtime/src/main/java/io/quarkus/runtime/util/ExceptionUtil.java index 99fbf4fdce04c..b27f844b3cf06 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/util/ExceptionUtil.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/util/ExceptionUtil.java @@ -86,6 +86,17 @@ public static Throwable getRootCause(Throwable exception) { return chain.isEmpty() ? null : chain.get(chain.size() - 1); } + public static boolean isAnyCauseInstanceOf(Throwable exception, Class classToCheck) { + Throwable curr = exception; + do { + if (classToCheck.isInstance(curr)) { + return true; + } + curr = curr.getCause(); + } while (curr != null); + return false; + } + /** * Creates and returns a new {@link Throwable} which has the following characteristics: *
    diff --git a/core/runtime/src/test/java/io/quarkus/runtime/util/ExceptionUtilTest.java b/core/runtime/src/test/java/io/quarkus/runtime/util/ExceptionUtilTest.java index c85696e57a8f0..e432bb0fa281f 100644 --- a/core/runtime/src/test/java/io/quarkus/runtime/util/ExceptionUtilTest.java +++ b/core/runtime/src/test/java/io/quarkus/runtime/util/ExceptionUtilTest.java @@ -13,6 +13,8 @@ import org.junit.jupiter.api.Test; +import io.quarkus.runtime.configuration.ConfigurationException; + /** * */ @@ -59,6 +61,11 @@ public void testGetRootCause() { assertEquals(NullPointerException.class, ExceptionUtil.getRootCause(new NullPointerException()).getClass()); } + @Test + public void testIsAnyCauseInstanceOf() { + assertTrue(ExceptionUtil.isAnyCauseInstanceOf(generateConfigurationException(), ConfigurationException.class)); + } + private Throwable generateException() { try { try { @@ -79,4 +86,26 @@ private Throwable generateException() { } throw new RuntimeException("Should not reach here"); } + + private Throwable generateConfigurationException() { + try { + try { + Integer.parseInt("23.23232"); + } catch (NumberFormatException nfe) { + throw new ConfigurationException("Incorrect param", nfe); + } + } catch (ConfigurationException ce) { + try { + throw new IOException("Request processing failed", ce); + } catch (IOException e) { + try { + throw new IOError(e); + } catch (IOError ie) { + return new RuntimeException("Unexpected exception", ie); + } + } + } + throw new RuntimeException("Should not reach here"); + } + }