From e360e4a75e738b8af455c4c10fc76c8f83d32e55 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 15 Oct 2020 12:04:39 -0700 Subject: [PATCH] Polish 'Add a FailureAnalyzer for ConfigDataNotFound' See gh-23633 --- ...ationNotFoundExceptionFailureAnalyzer.java | 21 ---- .../ConfigDataNotFoundFailureAnalyzer.java | 62 ++++++++++ .../main/resources/META-INF/spring.factories | 4 +- ...NotFoundExceptionFailureAnalyzerTests.java | 30 ----- ...onfigDataNotFoundFailureAnalyzerTests.java | 117 ++++++++++++++++++ 5 files changed, 181 insertions(+), 53 deletions(-) delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzer.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzerTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzer.java deleted file mode 100644 index 589edf784b4..00000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzer.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.springframework.boot.context.config; - -import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; -import org.springframework.boot.diagnostics.FailureAnalysis; - -/** - * - * An implementation of {@link AbstractFailureAnalyzer} to analyze failures caused by - * {@link ConfigDataLocationNotFoundException}. - * - * @author Michal Mlak - */ -public class ConfigDataLocationNotFoundExceptionFailureAnalyzer - extends AbstractFailureAnalyzer { - - @Override - protected FailureAnalysis analyze(Throwable rootFailure, ConfigDataLocationNotFoundException cause) { - return new FailureAnalysis(cause.getMessage(), null, cause); - } - -} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzer.java new file mode 100644 index 00000000000..c7b4966e52d --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzer.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2020 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.context.config; + +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.boot.origin.Origin; + +/** + * An implementation of {@link AbstractFailureAnalyzer} to analyze failures caused by + * {@link ConfigDataNotFoundException}. + * + * @author Michal Mlak + * @author Phillip Webb + */ +class ConfigDataNotFoundFailureAnalyzer extends AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, ConfigDataNotFoundException cause) { + ConfigDataLocation location = getLocation(cause); + Origin origin = Origin.from(location); + StringBuilder message = new StringBuilder( + String.format("Config data %s does not exist", cause.getReferenceDescription())); + StringBuilder action = new StringBuilder("Check that the value "); + if (location != null) { + action.append(String.format("'%s' ", location)); + } + if (origin != null) { + action.append(String.format("at %s ", origin)); + } + action.append("is correct"); + if (location != null && !location.isOptional()) { + action.append(String.format(", or prefix it with '%s'", ConfigDataLocation.OPTIONAL_PREFIX)); + } + return new FailureAnalysis(message.toString(), action.toString(), cause); + } + + private ConfigDataLocation getLocation(ConfigDataNotFoundException cause) { + if (cause instanceof ConfigDataLocationNotFoundException) { + return ((ConfigDataLocationNotFoundException) cause).getLocation(); + } + if (cause instanceof ConfigDataResourceNotFoundException) { + return ((ConfigDataResourceNotFoundException) cause).getLocation(); + } + return null; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 0ff91b31697..543f83941d9 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -58,6 +58,7 @@ org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ +org.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer,\ org.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer,\ org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ @@ -74,8 +75,7 @@ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\ -org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer,\ -org.springframework.boot.context.config.ConfigDataLocationNotFoundExceptionFailureAnalyzer +org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer # Failure Analysis Reporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzerTests.java deleted file mode 100644 index bcc2063adde..00000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionFailureAnalyzerTests.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.springframework.boot.context.config; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.diagnostics.FailureAnalysis; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * - * Tests for {@link ConfigDataLocationNotFoundExceptionFailureAnalyzer} - * - * @author Michal Mlak - */ -class ConfigDataLocationNotFoundExceptionFailureAnalyzerTests { - - private final ConfigDataLocationNotFoundExceptionFailureAnalyzer analyzer = new ConfigDataLocationNotFoundExceptionFailureAnalyzer(); - - @Test - void failureAnalysisForConfigDataLocationNotFound() { - ConfigDataLocation location = mock(ConfigDataLocation.class); - ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); - - FailureAnalysis result = analyzer.analyze(exception); - - assertThat(result.getDescription()).isEqualTo("Config data location '" + location + "' does not exist"); - assertThat(result.getAction()).isNull(); - } - -} \ No newline at end of file diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java new file mode 100644 index 00000000000..51bf0352c76 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2012-2020 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.context.config; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.boot.origin.Origin; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ConfigDataNotFoundFailureAnalyzer} + * + * @author Michal Mlak + * @author Phillip Webb + */ +class ConfigDataNotFoundFailureAnalyzerTests { + + private final ConfigDataNotFoundFailureAnalyzer analyzer = new ConfigDataNotFoundFailureAnalyzer(); + + @Test + void analyzeWhenConfigDataLocationNotFoundException() { + ConfigDataLocation location = ConfigDataLocation.of("test"); + ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); + FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result.getDescription()).isEqualTo("Config data location 'test' does not exist"); + assertThat(result.getAction()) + .isEqualTo("Check that the value 'test' is correct, or prefix it with 'optional:'"); + } + + @Test + void analyzeWhenOptionalConfigDataLocationNotFoundException() { + ConfigDataLocation location = ConfigDataLocation.of("optional:test"); + ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); + FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result.getDescription()).isEqualTo("Config data location 'optional:test' does not exist"); + assertThat(result.getAction()).isEqualTo("Check that the value 'optional:test' is correct"); + } + + @Test + void analyzeWhenConfigDataLocationWithOriginNotFoundException() { + ConfigDataLocation location = ConfigDataLocation.of("test").withOrigin(new TestOrigin("origin")); + ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); + FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result.getDescription()).isEqualTo("Config data location 'test' does not exist"); + assertThat(result.getAction()) + .isEqualTo("Check that the value 'test' at origin is correct, or prefix it with 'optional:'"); + } + + @Test + void analyzeWhenConfigDataResourceNotFoundException() { + ConfigDataResource resource = new TestConfigDataResource("myresource"); + ConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource); + FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result.getDescription()).isEqualTo("Config data resource 'myresource' does not exist"); + assertThat(result.getAction()).isEqualTo("Check that the value is correct"); + } + + @Test + void analyzeWhenConfigDataResourceWithLocationNotFoundException() { + ConfigDataLocation location = ConfigDataLocation.of("test"); + ConfigDataResource resource = new TestConfigDataResource("myresource"); + ConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource) + .withLocation(location); + FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result.getDescription()) + .isEqualTo("Config data resource 'myresource' via location 'test' does not exist"); + assertThat(result.getAction()) + .isEqualTo("Check that the value 'test' is correct, or prefix it with 'optional:'"); + } + + static class TestOrigin implements Origin { + + private final String string; + + TestOrigin(String string) { + this.string = string; + } + + @Override + public String toString() { + return this.string; + } + + } + + static class TestConfigDataResource extends ConfigDataResource { + + private final String string; + + TestConfigDataResource(String string) { + this.string = string; + } + + @Override + public String toString() { + return this.string; + } + + } + +}