From d63e3c3b535dd261c6afd2ee7d23c80606cb6378 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 15 Jul 2024 15:09:57 +0100 Subject: [PATCH] Rethrow failure on main thread Previously, if a failure occurred when evaluating conditions on a separate thread, an NPE would occur on the main thread as the expected array of outcomes was null. This commit avoids the NPE and the lack of error reporting by rethrowing on the main thread any failure that occurs on the separate thread that's spawned to parallelize the evaluation. Closes gh-41492 --- .../condition/OnClassCondition.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java index 9841bf802e6..d6c596e6841 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.MultiValueMap; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -142,8 +143,17 @@ class OnClassCondition extends FilteringSpringBootCondition { private volatile ConditionOutcome[] outcomes; + private volatile Throwable failure; + private ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) { - this.thread = new Thread(() -> this.outcomes = outcomesResolver.resolveOutcomes()); + this.thread = new Thread(() -> { + try { + this.outcomes = outcomesResolver.resolveOutcomes(); + } + catch (Throwable ex) { + this.failure = ex; + } + }); this.thread.start(); } @@ -155,6 +165,9 @@ class OnClassCondition extends FilteringSpringBootCondition { catch (InterruptedException ex) { Thread.currentThread().interrupt(); } + if (this.failure != null) { + ReflectionUtils.rethrowRuntimeException(this.failure); + } return this.outcomes; }