diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java index b47a8e0b73f..d253d6029d4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java @@ -103,13 +103,11 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration { public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension( GitProperties properties, ObjectProvider infoContributors) { List contributors = infoContributors.orderedStream() - .map((infoContributor) -> { - if (infoContributor instanceof GitInfoContributor) { - return new GitInfoContributor(properties, - InfoPropertiesInfoContributor.Mode.FULL); - } - return infoContributor; - }).collect(Collectors.toList()); + .map((infoContributor) -> (infoContributor instanceof GitInfoContributor) + ? new GitInfoContributor(properties, + InfoPropertiesInfoContributor.Mode.FULL) + : infoContributor) + .collect(Collectors.toList()); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java index d131a4dd37f..92a64c7ed6a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java @@ -104,13 +104,11 @@ public class CloudFoundryActuatorAutoConfiguration { public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension( GitProperties properties, ObjectProvider infoContributors) { List contributors = infoContributors.orderedStream() - .map((infoContributor) -> { - if (infoContributor instanceof GitInfoContributor) { - return new GitInfoContributor(properties, - InfoPropertiesInfoContributor.Mode.FULL); - } - return infoContributor; - }).collect(Collectors.toList()); + .map((infoContributor) -> (infoContributor instanceof GitInfoContributor) + ? new GitInfoContributor(properties, + InfoPropertiesInfoContributor.Mode.FULL) + : infoContributor) + .collect(Collectors.toList()); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java index a483efdc73b..567e2eb3c9e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.core.log.LogMessage; /** * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus. @@ -142,7 +143,7 @@ public class PrometheusMetricsExportAutoConfiguration { return new PushGateway(new URL(url)); } catch (MalformedURLException ex) { - logger.warn(String.format( + logger.warn(LogMessage.format( "Invalid PushGateway base url '%s': update your configuration to a valid URL", url)); return new PushGateway(url); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfiguration.java index 3e28e606d07..15396075af8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfiguration.java @@ -157,8 +157,8 @@ public class ManagementContextAutoConfiguration { AbstractApplicationContext context = (AbstractApplicationContext) this.applicationContext; List postProcessors = context .getBeanFactoryPostProcessors(); - return postProcessors.stream().anyMatch(( - postProcessor) -> postProcessor instanceof LazyInitializationBeanFactoryPostProcessor); + return postProcessors.stream().anyMatch( + LazyInitializationBeanFactoryPostProcessor.class::isInstance); } private void setClassLoaderIfPossible(ConfigurableApplicationContext child) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfigurationTests.java index 1cb4cd3291e..f665276c204 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfigurationTests.java @@ -56,7 +56,6 @@ public class ManagementContextAutoConfigurationTests { contextRunner.withPropertyValues("server.port=0", "management.server.port=0").run( (context) -> assertThat(tomcatStartedOccurencesIn(this.output.toString())) .isEqualTo(2)); - } private int tomcatStartedOccurencesIn(String output) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/trace/reactive/HttpTraceWebFilter.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/trace/reactive/HttpTraceWebFilter.java index 8d22e094ae6..811c2506d4c 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/trace/reactive/HttpTraceWebFilter.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/trace/reactive/HttpTraceWebFilter.java @@ -91,7 +91,7 @@ public class HttpTraceWebFilter implements WebFilter, Ordered { Principal principal, WebSession session) { ServerWebExchangeTraceableRequest request = new ServerWebExchangeTraceableRequest( exchange); - final HttpTrace trace = this.tracer.receivedRequest(request); + HttpTrace trace = this.tracer.receivedRequest(request); exchange.getResponse().beforeCommit(() -> { TraceableServerHttpResponse response = new TraceableServerHttpResponse( exchange.getResponse()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java index 8d35a4c71c8..077182fcba1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java @@ -38,15 +38,12 @@ class FlywayMigrationScriptMissingFailureAnalyzer .append("no migration scripts location is configured").toString(), "Check your Flyway configuration", cause); } - else { - description.append(String.format( - "none of the following migration scripts locations could be found:%n%n")); - cause.getLocations().forEach((location) -> description - .append(String.format("\t- %s%n", location))); - return new FailureAnalysis(description.toString(), - "Review the locations above or check your Flyway configuration", - cause); - } + description.append(String.format( + "none of the following migration scripts locations could be found:%n%n")); + cause.getLocations().forEach( + (location) -> description.append(String.format("\t- %s%n", location))); + return new FailureAnalysis(description.toString(), + "Review the locations above or check your Flyway configuration", cause); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java index 5ffe4bba4ba..8d9f0ac03d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java @@ -74,41 +74,44 @@ public class MongoReactiveAutoConfiguration { return new NettyDriverMongoClientSettingsBuilderCustomizer(settings); } - private static final class NettyDriverMongoClientSettingsBuilderCustomizer - implements MongoClientSettingsBuilderCustomizer, DisposableBean { + } - private final ObjectProvider settings; + /** + * {@link MongoClientSettingsBuilderCustomizer} to apply Mongo client settings. + */ + private static final class NettyDriverMongoClientSettingsBuilderCustomizer + implements MongoClientSettingsBuilderCustomizer, DisposableBean { - private volatile EventLoopGroup eventLoopGroup; + private final ObjectProvider settings; - private NettyDriverMongoClientSettingsBuilderCustomizer( - ObjectProvider settings) { - this.settings = settings; - } + private volatile EventLoopGroup eventLoopGroup; - @Override - public void customize(Builder builder) { - if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) { - NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - this.eventLoopGroup = eventLoopGroup; - builder.streamFactoryFactory(NettyStreamFactoryFactory.builder() - .eventLoopGroup(eventLoopGroup).build()); - } - } + private NettyDriverMongoClientSettingsBuilderCustomizer( + ObjectProvider settings) { + this.settings = settings; + } - @Override - public void destroy() { - EventLoopGroup eventLoopGroup = this.eventLoopGroup; - if (eventLoopGroup != null) { - eventLoopGroup.shutdownGracefully().awaitUninterruptibly(); - this.eventLoopGroup = null; - } + @Override + public void customize(Builder builder) { + if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) { + NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); + this.eventLoopGroup = eventLoopGroup; + builder.streamFactoryFactory(NettyStreamFactoryFactory.builder() + .eventLoopGroup(eventLoopGroup).build()); } + } - private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) { - return settings != null && settings.getStreamFactoryFactory() != null; + @Override + public void destroy() { + EventLoopGroup eventLoopGroup = this.eventLoopGroup; + if (eventLoopGroup != null) { + eventLoopGroup.shutdownGracefully().awaitUninterruptibly(); + this.eventLoopGroup = null; } + } + private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) { + return settings != null && settings.getStreamFactoryFactory() != null; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketNettyServerCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketNettyServerCustomizer.java index 7bfb68281bb..c6af4ef8b2e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketNettyServerCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketNettyServerCustomizer.java @@ -43,7 +43,7 @@ class RSocketNettyServerCustomizer implements NettyServerCustomizer { @Override public HttpServer apply(HttpServer httpServer) { - final ServerTransport.ConnectionAcceptor acceptor = RSocketFactory.receive() + ServerTransport.ConnectionAcceptor acceptor = RSocketFactory.receive() .acceptor(this.messageHandlerAcceptor).toConnectionAcceptor(); return httpServer.route((routes) -> routes.ws(this.mappingPath, WebsocketRouteTransport.newHandler(acceptor))); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketProperties.java index 531004d01cb..216952779f0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketProperties.java @@ -29,7 +29,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("spring.rsocket") public class RSocketProperties { - private Server server = new Server(); + private final Server server = new Server(); public Server getServer() { return this.server; diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java index 44f8c308e0f..52389c5d6e0 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java @@ -77,6 +77,8 @@ import org.springframework.web.context.support.GenericWebApplicationContext; */ public class SpringBootContextLoader extends AbstractContextLoader { + private static final String[] NO_ARGS = new String[0]; + @Override public ApplicationContext loadContext(MergedContextConfiguration config) throws Exception { @@ -155,7 +157,7 @@ public class SpringBootContextLoader extends AbstractContextLoader { protected String[] getArgs(MergedContextConfiguration config) { SpringBootTest annotation = AnnotatedElementUtils .findMergedAnnotation(config.getTestClass(), SpringBootTest.class); - return (annotation != null) ? annotation.args() : new String[0]; + return (annotation != null) ? annotation.args() : NO_ARGS; } private void setActiveProfiles(ConfigurableEnvironment environment, diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AsciidocBuilder.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AsciidocBuilder.java new file mode 100644 index 00000000000..104fec4d861 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AsciidocBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2019 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.configurationdocs; + +/** + * Simple builder to help construct Asciidoc markup. + * + * @author Phillip Webb + */ +class AsciidocBuilder { + + private static final String NEWLINE = System.lineSeparator(); + + private final StringBuilder content; + + AsciidocBuilder() { + this.content = new StringBuilder(); + } + + public AsciidocBuilder appendln(Object... items) { + append(items); + append(NEWLINE); + return this; + } + + public AsciidocBuilder append(Object... items) { + for (Object item : items) { + this.content.append(item); + } + return this; + } + + @Override + public String toString() { + return this.content.toString(); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundKeyEntry.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntry.java similarity index 72% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundKeyEntry.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntry.java index 8192aeaff3a..1c58f2cc668 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundKeyEntry.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntry.java @@ -27,29 +27,30 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope * * @author Brian Clozel */ -class CompoundKeyEntry extends AbstractConfigurationEntry { +class CompoundConfigurationTableEntry extends ConfigurationTableEntry { private Set configurationKeys; private String description; - CompoundKeyEntry(String key, String description) { + CompoundConfigurationTableEntry(String key, String description) { this.key = key; this.description = description; this.configurationKeys = new TreeSet<>(); } void addConfigurationKeys(ConfigurationMetadataProperty... properties) { - Stream.of(properties) - .forEach((property) -> this.configurationKeys.add(property.getId())); + Stream.of(properties).map(ConfigurationMetadataProperty::getId) + .forEach(this.configurationKeys::add); } @Override - public void writeAsciidoc(StringBuilder builder) { + public void write(AsciidocBuilder builder) { builder.append("|`+++"); - this.configurationKeys.forEach((key) -> builder.append(key).append(NEWLINE)); - builder.append("+++`").append(NEWLINE).append("|").append(NEWLINE).append("|+++") - .append(this.description).append("+++").append(NEWLINE); + this.configurationKeys.forEach(builder::appendln); + builder.appendln("+++`"); + builder.appendln("|"); + builder.appendln("|+++", this.description, "+++"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationMetadataDocumentWriter.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationMetadataDocumentWriter.java index e410e56bc37..2c1d6be82f4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationMetadataDocumentWriter.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationMetadataDocumentWriter.java @@ -29,7 +29,6 @@ import java.util.Map; import java.util.stream.Collectors; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; -import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; /** @@ -39,8 +38,21 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepos */ public class ConfigurationMetadataDocumentWriter { - public void writeDocument(Path outputDirPath, DocumentOptions options, - InputStream... metadataInput) throws IOException { + public void writeDocument(Path outputDirectory, DocumentOptions options, + InputStream... metadata) throws IOException { + assertValidOutputDirectory(outputDirectory); + if (!Files.exists(outputDirectory)) { + Files.createDirectory(outputDirectory); + } + assertMetadata(metadata); + List tables = createConfigTables( + getMetadataProperties(metadata), options); + for (ConfigurationTable table : tables) { + writeConfigurationTable(table, outputDirectory); + } + } + + private void assertValidOutputDirectory(Path outputDirPath) { if (outputDirPath == null) { throw new IllegalArgumentException("output path should not be null"); } @@ -48,64 +60,33 @@ public class ConfigurationMetadataDocumentWriter { throw new IllegalArgumentException( "output path already exists and is not a directory"); } - else if (!Files.exists(outputDirPath)) { - Files.createDirectory(outputDirPath); - } - if (metadataInput == null || metadataInput.length < 1) { + } + + private void assertMetadata(InputStream... metadata) { + if (metadata == null || metadata.length < 1) { throw new IllegalArgumentException("missing input metadata"); } + } - ConfigurationMetadataRepository configRepository = ConfigurationMetadataRepositoryJsonBuilder - .create(metadataInput).build(); - Map allProperties = configRepository - .getAllProperties(); - - List tables = createConfigTables(allProperties, options); - - for (ConfigurationTable table : tables) { - Path outputFilePath = outputDirPath.resolve(table.getId() + ".adoc"); - Files.deleteIfExists(outputFilePath); - Files.createFile(outputFilePath); - try (OutputStream outputStream = Files.newOutputStream(outputFilePath)) { - outputStream - .write(table.toAsciidocTable().getBytes(StandardCharsets.UTF_8)); - } - } + private Map getMetadataProperties( + InputStream... metadata) throws IOException { + ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder + .create(metadata); + return builder.build().getAllProperties(); } private List createConfigTables( - Map allProperties, + Map metadataProperties, DocumentOptions options) { - - final List tables = new ArrayList<>(); - final List unmappedKeys = allProperties.values().stream() - .filter((prop) -> !prop.isDeprecated()).map((prop) -> prop.getId()) - .collect(Collectors.toList()); - - final Map overrides = getOverrides(allProperties, - unmappedKeys, options); - - options.getMetadataSections().forEach((id, keyPrefixes) -> { - ConfigurationTable table = new ConfigurationTable(id); - tables.add(table); - for (String keyPrefix : keyPrefixes) { - List matchingOverrides = overrides.keySet().stream() - .filter((overrideKey) -> overrideKey.startsWith(keyPrefix)) - .collect(Collectors.toList()); - matchingOverrides - .forEach((match) -> table.addEntry(overrides.remove(match))); - } - List matchingKeys = unmappedKeys.stream() - .filter((key) -> keyPrefixes.stream().anyMatch(key::startsWith)) - .collect(Collectors.toList()); - for (String matchingKey : matchingKeys) { - ConfigurationMetadataProperty property = allProperties.get(matchingKey); - table.addEntry(new SingleKeyEntry(property)); - - } - unmappedKeys.removeAll(matchingKeys); - }); - + List tables = new ArrayList<>(); + List unmappedKeys = metadataProperties.values().stream() + .filter((property) -> !property.isDeprecated()) + .map(ConfigurationMetadataProperty::getId).collect(Collectors.toList()); + Map overrides = getOverrides( + metadataProperties, unmappedKeys, options); + options.getMetadataSections().forEach( + (id, keyPrefixes) -> tables.add(createConfigTable(metadataProperties, + unmappedKeys, overrides, id, keyPrefixes))); if (!unmappedKeys.isEmpty()) { throw new IllegalStateException( "The following keys were not written to the documentation: " @@ -116,22 +97,21 @@ public class ConfigurationMetadataDocumentWriter { "The following keys were not written to the documentation: " + String.join(", ", overrides.keySet())); } - return tables; } - private Map getOverrides( - Map allProperties, + private Map getOverrides( + Map metadataProperties, List unmappedKeys, DocumentOptions options) { - final Map overrides = new HashMap<>(); - + Map overrides = new HashMap<>(); options.getOverrides().forEach((keyPrefix, description) -> { - final CompoundKeyEntry entry = new CompoundKeyEntry(keyPrefix, description); + CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry( + keyPrefix, description); List matchingKeys = unmappedKeys.stream() .filter((key) -> key.startsWith(keyPrefix)) .collect(Collectors.toList()); for (String matchingKey : matchingKeys) { - entry.addConfigurationKeys(allProperties.get(matchingKey)); + entry.addConfigurationKeys(metadataProperties.get(matchingKey)); } overrides.put(keyPrefix, entry); unmappedKeys.removeAll(matchingKeys); @@ -139,4 +119,37 @@ public class ConfigurationMetadataDocumentWriter { return overrides; } + private ConfigurationTable createConfigTable( + Map metadataProperties, + List unmappedKeys, + Map overrides, String id, + List keyPrefixes) { + ConfigurationTable table = new ConfigurationTable(id); + for (String keyPrefix : keyPrefixes) { + List matchingOverrides = overrides.keySet().stream() + .filter((overrideKey) -> overrideKey.startsWith(keyPrefix)) + .collect(Collectors.toList()); + matchingOverrides.forEach((match) -> table.addEntry(overrides.remove(match))); + } + List matchingKeys = unmappedKeys.stream() + .filter((key) -> keyPrefixes.stream().anyMatch(key::startsWith)) + .collect(Collectors.toList()); + for (String matchingKey : matchingKeys) { + ConfigurationMetadataProperty property = metadataProperties.get(matchingKey); + table.addEntry(new SingleConfigurationTableEntry(property)); + } + unmappedKeys.removeAll(matchingKeys); + return table; + } + + private void writeConfigurationTable(ConfigurationTable table, Path outputDirectory) + throws IOException { + Path outputFilePath = outputDirectory.resolve(table.getId() + ".adoc"); + Files.deleteIfExists(outputFilePath); + Files.createFile(outputFilePath); + try (OutputStream outputStream = Files.newOutputStream(outputFilePath)) { + outputStream.write(table.toAsciidocTable().getBytes(StandardCharsets.UTF_8)); + } + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTable.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTable.java index d9d6245fbf3..f1954099037 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTable.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTable.java @@ -27,11 +27,9 @@ import java.util.TreeSet; */ class ConfigurationTable { - private static final String NEWLINE = System.lineSeparator(); - private final String id; - private final Set entries; + private final Set entries; ConfigurationTable(String id) { this.id = id; @@ -42,20 +40,21 @@ class ConfigurationTable { return this.id; } - void addEntry(AbstractConfigurationEntry... entries) { + void addEntry(ConfigurationTableEntry... entries) { this.entries.addAll(Arrays.asList(entries)); } String toAsciidocTable() { - final StringBuilder builder = new StringBuilder(); - builder.append("[cols=\"1,1,2\", options=\"header\"]").append(NEWLINE); - builder.append("|===").append(NEWLINE).append("|Key|Default Value|Description") - .append(NEWLINE).append(NEWLINE); + AsciidocBuilder builder = new AsciidocBuilder(); + builder.appendln("[cols=\"1,1,2\", options=\"header\"]"); + builder.appendln("|==="); + builder.appendln("|Key|Default Value|Description"); + builder.appendln(); this.entries.forEach((entry) -> { - entry.writeAsciidoc(builder); - builder.append(NEWLINE); + entry.write(builder); + builder.appendln(); }); - return builder.append("|===").append(NEWLINE).toString(); + return builder.appendln("|===").toString(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AbstractConfigurationEntry.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTableEntry.java similarity index 64% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AbstractConfigurationEntry.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTableEntry.java index 151c000d49a..2107c328a64 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/AbstractConfigurationEntry.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/ConfigurationTableEntry.java @@ -16,17 +16,12 @@ package org.springframework.boot.configurationdocs; -import java.util.Objects; - /** * Abstract class for entries in {@link ConfigurationTable}. * * @author Brian Clozel */ -abstract class AbstractConfigurationEntry - implements Comparable { - - protected static final String NEWLINE = System.lineSeparator(); +abstract class ConfigurationTableEntry implements Comparable { protected String key; @@ -34,27 +29,27 @@ abstract class AbstractConfigurationEntry return this.key; } - public abstract void writeAsciidoc(StringBuilder builder); + public abstract void write(AsciidocBuilder builder); @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (o == null || getClass() != o.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } - AbstractConfigurationEntry that = (AbstractConfigurationEntry) o; - return this.key.equals(that.key); + ConfigurationTableEntry other = (ConfigurationTableEntry) obj; + return this.key.equals(other.key); } @Override public int hashCode() { - return Objects.hash(this.key); + return this.key.hashCode(); } @Override - public int compareTo(AbstractConfigurationEntry other) { + public int compareTo(ConfigurationTableEntry other) { return this.key.compareTo(other.getKey()); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntry.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntry.java new file mode 100644 index 00000000000..7ee111539d9 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntry.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2019 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.configurationdocs; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; + +/** + * Table entry containing a single configuration property. + * + * @author Brian Clozel + */ +class SingleConfigurationTableEntry extends ConfigurationTableEntry { + + private final String description; + + private final String defaultValue; + + SingleConfigurationTableEntry(ConfigurationMetadataProperty property) { + this.key = property.getId(); + if (property.getType() != null + && property.getType().startsWith("java.util.Map")) { + this.key += ".*"; + } + this.description = property.getDescription(); + this.defaultValue = getDefaultValue(property.getDefaultValue()); + } + + private String getDefaultValue(Object defaultValue) { + if (defaultValue == null) { + return null; + } + if (defaultValue.getClass().isArray()) { + return Arrays.stream((Object[]) defaultValue).map(Object::toString) + .collect(Collectors.joining("," + System.lineSeparator())); + } + return defaultValue.toString(); + } + + @Override + public void write(AsciidocBuilder builder) { + builder.appendln("|`+", this.key, "+`"); + writeDefaultValue(builder); + writeDescription(builder); + builder.appendln(); + } + + private void writeDefaultValue(AsciidocBuilder builder) { + String defaultValue = (this.defaultValue != null) ? this.defaultValue : ""; + defaultValue = defaultValue.replace("\\", "\\\\").replace("|", + "{vbar}" + System.lineSeparator()); + if (defaultValue.isEmpty()) { + builder.appendln("|"); + } + else { + builder.appendln("|`+", defaultValue, "+`"); + } + } + + private void writeDescription(AsciidocBuilder builder) { + if (this.description == null || this.description.isEmpty()) { + builder.append("|"); + } + else { + builder.append("|+++", this.description, "+++"); + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleKeyEntry.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleKeyEntry.java deleted file mode 100644 index e1af08857b5..00000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/main/java/org/springframework/boot/configurationdocs/SingleKeyEntry.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012-2019 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.configurationdocs; - -import java.util.Arrays; -import java.util.stream.Collectors; - -import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; - -/** - * Table entry containing a single configuration property. - * - * @author Brian Clozel - */ -class SingleKeyEntry extends AbstractConfigurationEntry { - - private String defaultValue; - - private String description; - - SingleKeyEntry(ConfigurationMetadataProperty property) { - - this.key = property.getId(); - if (property.getType() != null - && property.getType().startsWith("java.util.Map")) { - this.key += ".*"; - } - - this.description = property.getDescription(); - - if (property.getDefaultValue() != null) { - if (property.getDefaultValue().getClass().isArray()) { - this.defaultValue = Arrays.stream((Object[]) property.getDefaultValue()) - .map(Object::toString).collect(Collectors.joining("," + NEWLINE)); - } - else { - this.defaultValue = property.getDefaultValue().toString(); - } - } - } - - @Override - public void writeAsciidoc(StringBuilder builder) { - builder.append("|`+").append(this.key).append("+`").append(NEWLINE); - String defaultValue = processDefaultValue(); - if (!defaultValue.isEmpty()) { - builder.append("|`+").append(defaultValue).append("+`").append(NEWLINE); - } - else { - builder.append("|").append(NEWLINE); - } - if (this.description != null) { - builder.append("|+++").append(this.description).append("+++"); - } - else { - builder.append("|"); - } - builder.append(NEWLINE); - } - - private String processDefaultValue() { - if (this.defaultValue != null && !this.defaultValue.isEmpty()) { - return this.defaultValue.replace("\\", "\\\\").replace("|", - "{vbar}" + NEWLINE); - } - return ""; - } - -} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundKeyEntryTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntryTests.java similarity index 85% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundKeyEntryTests.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntryTests.java index 51ffe017bcd..65a663630cb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundKeyEntryTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/CompoundConfigurationTableEntryTests.java @@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope import static org.assertj.core.api.Assertions.assertThat; /** + * Tests for {@link CompoundConfigurationTableEntry}. + * * @author Brian Clozel */ -public class CompoundKeyEntryTests { +public class CompoundConfigurationTableEntryTests { private static String NEWLINE = System.lineSeparator(); @@ -34,21 +36,17 @@ public class CompoundKeyEntryTests { ConfigurationMetadataProperty firstProp = new ConfigurationMetadataProperty(); firstProp.setId("spring.test.first"); firstProp.setType("java.lang.String"); - ConfigurationMetadataProperty secondProp = new ConfigurationMetadataProperty(); secondProp.setId("spring.test.second"); secondProp.setType("java.lang.String"); - ConfigurationMetadataProperty thirdProp = new ConfigurationMetadataProperty(); thirdProp.setId("spring.test.third"); thirdProp.setType("java.lang.String"); - - CompoundKeyEntry entry = new CompoundKeyEntry("spring.test", - "This is a description."); + CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry( + "spring.test", "This is a description."); entry.addConfigurationKeys(firstProp, secondProp, thirdProp); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+++spring.test.first" + NEWLINE + "spring.test.second" + NEWLINE + "spring.test.third" + NEWLINE + "+++`" + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/ConfigurationTableTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/ConfigurationTableTests.java index 915ec8f71cf..2e80928ff81 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/ConfigurationTableTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/ConfigurationTableTests.java @@ -23,6 +23,8 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope import static org.assertj.core.api.Assertions.assertThat; /** + * Tests for {@link ConfigurationTable}. + * * @author Brian Clozel */ public class ConfigurationTableTests { @@ -32,22 +34,18 @@ public class ConfigurationTableTests { @Test public void simpleTable() { ConfigurationTable table = new ConfigurationTable("test"); - ConfigurationMetadataProperty first = new ConfigurationMetadataProperty(); first.setId("spring.test.prop"); first.setDefaultValue("something"); first.setDescription("This is a description."); first.setType("java.lang.String"); - ConfigurationMetadataProperty second = new ConfigurationMetadataProperty(); second.setId("spring.test.other"); second.setDefaultValue("other value"); second.setDescription("This is another description."); second.setType("java.lang.String"); - - table.addEntry(new SingleKeyEntry(first)); - table.addEntry(new SingleKeyEntry(second)); - + table.addEntry(new SingleConfigurationTableEntry(first)); + table.addEntry(new SingleConfigurationTableEntry(second)); assertThat(table.toAsciidocTable()) .isEqualTo("[cols=\"1,1,2\", options=\"header\"]" + NEWLINE + "|===" + NEWLINE + "|Key|Default Value|Description" + NEWLINE + NEWLINE diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleKeyEntryTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntryTests.java similarity index 77% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleKeyEntryTests.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntryTests.java index 59cddf26444..717c075898d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleKeyEntryTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-docs/src/test/java/org/springframework/boot/configurationdocs/SingleConfigurationTableEntryTests.java @@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope import static org.assertj.core.api.Assertions.assertThat; /** + * Tests for {@link SingleConfigurationTableEntry}. + * * @author Brian Clozel */ -public class SingleKeyEntryTests { +public class SingleConfigurationTableEntryTests { private static String NEWLINE = System.lineSeparator(); @@ -36,11 +38,9 @@ public class SingleKeyEntryTests { property.setDefaultValue("something"); property.setDescription("This is a description."); property.setType("java.lang.String"); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+something+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); } @@ -51,11 +51,9 @@ public class SingleKeyEntryTests { property.setId("spring.test.prop"); property.setDescription("This is a description."); property.setType("java.lang.String"); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); } @@ -67,11 +65,9 @@ public class SingleKeyEntryTests { property.setDefaultValue("first|second"); property.setDescription("This is a description."); property.setType("java.lang.String"); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+first{vbar}" + NEWLINE + "second+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); @@ -84,11 +80,9 @@ public class SingleKeyEntryTests { property.setDefaultValue("first\\second"); property.setDescription("This is a description."); property.setType("java.lang.String"); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()) .isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+first\\\\second+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); @@ -100,11 +94,9 @@ public class SingleKeyEntryTests { property.setId("spring.test.prop"); property.setDescription("This is a description."); property.setType("java.util.Map"); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+spring.test.prop.*+`" + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); } @@ -117,11 +109,9 @@ public class SingleKeyEntryTests { property.setDescription("This is a description."); property.setType("java.util.List"); property.setDefaultValue(defaultValue); - - SingleKeyEntry entry = new SingleKeyEntry(property); - StringBuilder builder = new StringBuilder(); - entry.writeAsciidoc(builder); - + SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); + AsciidocBuilder builder = new AsciidocBuilder(); + entry.write(builder); assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+first," + NEWLINE + "second," + NEWLINE + "third+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java index e83f3930b97..0d90046ae36 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java @@ -17,6 +17,7 @@ package org.springframework.boot.configurationprocessor; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; @@ -61,30 +62,36 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor defaultValue = (List) environment - .getAnnotationElementValues(defaultValueAnnotation).get("value"); - if (defaultValue != null) { - try { - TypeMirror specificType = determineSpecificType(environment); - if (defaultValue.size() == 1) { - return coerceValue(specificType, defaultValue.get(0)); - } - return defaultValue.stream() - .map((value) -> coerceValue(specificType, value)) - .collect(Collectors.toList()); - } - catch (IllegalArgumentException ex) { - environment.getMessager().printMessage(Kind.ERROR, ex.getMessage(), - element, defaultValueAnnotation); + AnnotationMirror annotation = environment.getDefaultValueAnnotation(element); + List defaultValue = getDefaultValue(environment, annotation); + if (defaultValue != null) { + try { + TypeMirror specificType = determineSpecificType(environment); + if (defaultValue.size() == 1) { + return coerceValue(specificType, defaultValue.get(0)); } + return defaultValue.stream() + .map((value) -> coerceValue(specificType, value)) + .collect(Collectors.toList()); + } + catch (IllegalArgumentException ex) { + environment.getMessager().printMessage(Kind.ERROR, ex.getMessage(), + element, annotation); } } return null; } + @SuppressWarnings("unchecked") + private List getDefaultValue(MetadataGenerationEnvironment environment, + AnnotationMirror annotation) { + if (annotation == null) { + return null; + } + Map values = environment.getAnnotationElementValues(annotation); + return (List) values.get("value"); + } + private TypeMirror determineSpecificType(MetadataGenerationEnvironment environment) { TypeMirror candidate = getSource().asType(); TypeMirror elementCandidate = environment.getTypeUtils() diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java index ba3bef8d303..10bd0bed46a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java @@ -17,6 +17,7 @@ package org.springframework.boot.configurationprocessor; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -49,7 +50,24 @@ class MetadataGenerationEnvironment { private static final String NULLABLE_ANNOTATION = "org.springframework.lang.Nullable"; - private final Set typeExcludes; + private static final Set TYPE_EXCLUDES; + static { + Set excludes = new HashSet<>(); + excludes.add("com.zaxxer.hikari.IConnectionCustomizer"); + excludes.add("groovy.text.markup.MarkupTemplateEngine"); + excludes.add("java.io.Writer"); + excludes.add("java.io.PrintWriter"); + excludes.add("java.lang.ClassLoader"); + excludes.add("java.util.concurrent.ThreadFactory"); + excludes.add("javax.jms.XAConnectionFactory"); + excludes.add("javax.sql.DataSource"); + excludes.add("javax.sql.XADataSource"); + excludes.add("org.apache.tomcat.jdbc.pool.PoolConfiguration"); + excludes.add("org.apache.tomcat.jdbc.pool.Validator"); + excludes.add("org.flywaydb.core.api.callback.FlywayCallback"); + excludes.add("org.flywaydb.core.api.resolver.MigrationResolver"); + TYPE_EXCLUDES = Collections.unmodifiableSet(excludes); + } private final TypeUtils typeUtils; @@ -79,7 +97,6 @@ class MetadataGenerationEnvironment { String deprecatedConfigurationPropertyAnnotation, String defaultValueAnnotation, String endpointAnnotation, String readOperationAnnotation) { - this.typeExcludes = determineTypeExcludes(); this.typeUtils = new TypeUtils(environment); this.elements = environment.getElementUtils(); this.messager = environment.getMessager(); @@ -92,24 +109,6 @@ class MetadataGenerationEnvironment { this.readOperationAnnotation = readOperationAnnotation; } - private static Set determineTypeExcludes() { - Set excludes = new HashSet<>(); - excludes.add("com.zaxxer.hikari.IConnectionCustomizer"); - excludes.add("groovy.text.markup.MarkupTemplateEngine"); - excludes.add("java.io.Writer"); - excludes.add("java.io.PrintWriter"); - excludes.add("java.lang.ClassLoader"); - excludes.add("java.util.concurrent.ThreadFactory"); - excludes.add("javax.jms.XAConnectionFactory"); - excludes.add("javax.sql.DataSource"); - excludes.add("javax.sql.XADataSource"); - excludes.add("org.apache.tomcat.jdbc.pool.PoolConfiguration"); - excludes.add("org.apache.tomcat.jdbc.pool.Validator"); - excludes.add("org.flywaydb.core.api.callback.FlywayCallback"); - excludes.add("org.flywaydb.core.api.resolver.MigrationResolver"); - return excludes; - } - private static FieldValuesParser resolveFieldValuesParser(ProcessingEnvironment env) { try { return new JavaCompilerFieldValuesParser(env); @@ -147,7 +146,7 @@ class MetadataGenerationEnvironment { if (typeName.endsWith("[]")) { typeName = typeName.substring(0, typeName.length() - 2); } - return this.typeExcludes.contains(typeName); + return TYPE_EXCLUDES.contains(typeName); } public boolean isDeprecated(Element element) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java index 1b0454ef539..50fdd9b10cb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java @@ -164,9 +164,8 @@ class TypeUtils { return this.types.getDeclaredType(this.env.getElementUtils() .getTypeElement(Object.class.getName())); } - else { // return type argument to Collection<...> - return declaredType.getTypeArguments().get(0); - } + // return type argument to Collection<...> + return declaredType.getTypeArguments().get(0); } // recursively walk the supertypes, looking for Collection<...> diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java index 170c2e82ac3..c778c46cb2e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java @@ -17,10 +17,10 @@ package org.springframework.boot.cloud; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; -import org.springframework.util.StringUtils; /** * Simple detection for well known cloud platforms. For more advanced cloud provider @@ -73,27 +73,42 @@ public enum CloudPlatform { * Kubernetes platform. */ KUBERNETES { + + private static final String SERVICE_HOST_SUFFIX = "_SERVICE_HOST"; + + private static final String SERVICE_PORT_SUFFIX = "_SERVICE_PORT"; + @Override public boolean isActive(Environment environment) { if (environment instanceof ConfigurableEnvironment) { - MapPropertySource propertySource = (MapPropertySource) ((ConfigurableEnvironment) environment) - .getPropertySources() - .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); - if (propertySource != null) { - for (String name : propertySource.getPropertyNames()) { - if (name.endsWith("_SERVICE_HOST")) { - String serviceName = StringUtils.split(name, - "_SERVICE_HOST")[0]; - if (propertySource - .getProperty(serviceName + "_SERVICE_PORT") != null) { - return true; - } - } + return isActive((ConfigurableEnvironment) environment); + } + return false; + } + + private boolean isActive(ConfigurableEnvironment environment) { + PropertySource environmentPropertySource = environment.getPropertySources() + .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + if (environmentPropertySource instanceof EnumerablePropertySource) { + return isActive((EnumerablePropertySource) environmentPropertySource); + } + return false; + } + + private boolean isActive(EnumerablePropertySource environmentPropertySource) { + for (String propertyName : environmentPropertySource.getPropertyNames()) { + if (propertyName.endsWith(SERVICE_HOST_SUFFIX)) { + String serviceName = propertyName.substring(0, + propertyName.length() - SERVICE_HOST_SUFFIX.length()); + if (environmentPropertySource + .getProperty(serviceName + SERVICE_PORT_SUFFIX) != null) { + return true; } } } return false; } + }; /** diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index fbb272142ad..a50b7f41033 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -116,6 +116,9 @@ public class ConfigFileApplicationListener private static final Bindable STRING_ARRAY = Bindable.of(String[].class); + private static final Bindable> STRING_LIST = Bindable + .listOf(String.class); + /** * The "active profiles" property name. */ @@ -701,18 +704,6 @@ public class ConfigFileApplicationListener return new LinkedHashSet<>(list); } - /** - * This ensures that the order of active profiles in the {@link Environment} - * matches the order in which the profiles were processed. - * @param processedProfiles the processed profiles - */ - private void resetEnvironmentProfiles(List processedProfiles) { - String[] names = processedProfiles.stream() - .filter((profile) -> profile != null && !profile.isDefaultProfile()) - .map(Profile::getName).toArray(String[]::new); - this.environment.setActiveProfiles(names); - } - private void addLoadedPropertySources() { MutablePropertySources destination = this.environment.getPropertySources(); List loaded = new ArrayList<>(this.loaded.values()); @@ -773,8 +764,7 @@ public class ConfigFileApplicationListener } private List getDefaultProfiles(Binder binder, String property) { - return Arrays - .asList(binder.bind(property, STRING_ARRAY).orElse(new String[] {})); + return binder.bind(property, STRING_LIST).orElse(Collections.emptyList()); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanDefinitionRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanDefinitionRegistrar.java index ccf4c285818..2636cf6bc46 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanDefinitionRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanDefinitionRegistrar.java @@ -91,11 +91,9 @@ final class ConfigurationPropertiesBeanDefinitionRegistrar { if (canBindAtCreationTime(type)) { return ConfigurationPropertiesBeanDefinition.from(beanFactory, name, type); } - else { - GenericBeanDefinition definition = new GenericBeanDefinition(); - definition.setBeanClass(type); - return definition; - } + GenericBeanDefinition definition = new GenericBeanDefinition(); + definition.setBeanClass(type); + return definition; } private static boolean canBindAtCreationTime(Class type) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java index a2b21cd8dda..ebae95f75f1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java @@ -72,18 +72,24 @@ class ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegist scanner.addIncludeFilter(new AnnotationTypeFilter(ConfigurationProperties.class)); for (String basePackage : packages) { if (StringUtils.hasText(basePackage)) { - for (BeanDefinition candidate : scanner - .findCandidateComponents(basePackage)) { - String beanClassName = candidate.getBeanClassName(); - try { - Class type = ClassUtils.forName(beanClassName, null); - ConfigurationPropertiesBeanDefinitionRegistrar.register(registry, - beanFactory, type); - } - catch (ClassNotFoundException ex) { - // Ignore - } - } + scan(beanFactory, registry, scanner, basePackage); + } + } + } + + private void scan(ConfigurableListableBeanFactory beanFactory, + BeanDefinitionRegistry registry, + ClassPathScanningCandidateComponentProvider scanner, String basePackage) + throws LinkageError { + for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) { + String beanClassName = candidate.getBeanClassName(); + try { + Class type = ClassUtils.forName(beanClassName, null); + ConfigurationPropertiesBeanDefinitionRegistrar.register(registry, + beanFactory, type); + } + catch (ClassNotFoundException ex) { + // Ignore } } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesImportSelector.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesImportSelector.java index e1281601a98..43c0c7da2f1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesImportSelector.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesImportSelector.java @@ -77,9 +77,8 @@ class EnableConfigurationPropertiesImportSelector implements ImportSelector { } private List> collectClasses(List values) { - return values.stream().flatMap((value) -> Arrays.stream((Object[]) value)) - .map((o) -> (Class) o).filter((type) -> void.class != type) - .collect(Collectors.toList()); + return values.stream().flatMap((value) -> Arrays.stream((Class[]) value)) + .filter((type) -> void.class != type).collect(Collectors.toList()); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ConstructorParametersBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ConstructorParametersBinder.java index 30cf52ab50b..08d0b0eb0b7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ConstructorParametersBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ConstructorParametersBinder.java @@ -21,6 +21,7 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -58,30 +59,25 @@ class ConstructorParametersBinder implements BeanBinder { private List bind(BeanPropertyBinder propertyBinder, Bean bean, BindConverter converter) { - List boundParams = new ArrayList<>(); - for (ConstructorParameter parameter : bean.getParameters().values()) { - Object bound = bind(parameter, propertyBinder); - if (bound == null) { - bound = getDefaultValue(parameter, converter); + Collection parameters = bean.getParameters().values(); + List boundParameters = new ArrayList<>(parameters.size()); + for (ConstructorParameter parameter : parameters) { + Object boundParameter = bind(parameter, propertyBinder); + if (boundParameter == null) { + boundParameter = getDefaultValue(parameter, converter); } - boundParams.add(bound); + boundParameters.add(boundParameter); } - return boundParams; + return boundParameters; } private Object getDefaultValue(ConstructorParameter parameter, BindConverter converter) { - if (parameter.getDefaultValue() != null) { - return converter.convert(parameter.getDefaultValue(), parameter.getType(), - parameter.getAnnotations()); - } - else { - Class resolve = parameter.getType().resolve(); - if (resolve != null && resolve.isPrimitive()) { - return null; - } + if (parameter.getDefaultValue() == null) { + return null; } - return null; + return converter.convert(parameter.getDefaultValue(), parameter.getType(), + parameter.getAnnotations()); } private Object bind(ConstructorParameter parameter, @@ -112,20 +108,9 @@ class ConstructorParametersBinder implements BeanBinder { return null; } if (KOTLIN_PRESENT && KotlinDetector.isKotlinType(type)) { - Constructor primaryConstructor = BeanUtils - .findPrimaryConstructor(type); - if (primaryConstructor != null - && primaryConstructor.getParameterCount() > 0) { - return KotlinBeanProvider.get(primaryConstructor); - } - } - else { - Constructor[] constructors = type.getDeclaredConstructors(); - if (constructors.length == 1 && constructors[0].getParameterCount() > 0) { - return SimpleBeanProvider.get(constructors[0]); - } + return KotlinBeanProvider.get(type); } - return null; + return SimpleBeanProvider.get(type); } public Map getParameters() { @@ -138,49 +123,28 @@ class ConstructorParametersBinder implements BeanBinder { } - /** - * A simple bean provider that uses `-parameters` to extract the parameter names. - */ - private static class SimpleBeanProvider { - - public static Bean get(Constructor constructor) { - return new Bean(constructor, parseParameters(constructor)); - } - - private static Map parseParameters( - Constructor constructor) { - Map parameters = new LinkedHashMap<>(); - for (Parameter parameter : constructor.getParameters()) { - String name = parameter.getName(); - DefaultValue[] annotationsByType = parameter - .getAnnotationsByType(DefaultValue.class); - String[] defaultValue = (annotationsByType.length > 0) - ? annotationsByType[0].value() : null; - parameters.computeIfAbsent(name, - (s) -> new ConstructorParameter(name, - ResolvableType.forClass(parameter.getType()), - parameter.getDeclaredAnnotations(), defaultValue)); - } - return parameters; - } - - } - /** * A bean provider for a Kotlin class. Uses the Kotlin constructor to extract the * parameter names. */ private static class KotlinBeanProvider { - public static Bean get(Constructor constructor) { + public static Bean get(Class type) { + Constructor primaryConstructor = BeanUtils.findPrimaryConstructor(type); + if (primaryConstructor != null + && primaryConstructor.getParameterCount() > 0) { + return get(primaryConstructor); + } + return null; + } + + private static Bean get(Constructor constructor) { KFunction kotlinConstructor = ReflectJvmMapping .getKotlinFunction(constructor); if (kotlinConstructor != null) { return new Bean(constructor, parseParameters(kotlinConstructor)); } - else { - return SimpleBeanProvider.get(constructor); - } + return SimpleBeanProvider.get(constructor); } private static Map parseParameters( @@ -199,6 +163,42 @@ class ConstructorParametersBinder implements BeanBinder { } + /** + * A simple bean provider that uses `-parameters` to extract the parameter names. + */ + private static class SimpleBeanProvider { + + public static Bean get(Class type) { + Constructor[] constructors = type.getDeclaredConstructors(); + if (constructors.length == 1 && constructors[0].getParameterCount() > 0) { + return SimpleBeanProvider.get(constructors[0]); + } + return null; + } + + public static Bean get(Constructor constructor) { + return new Bean(constructor, parseParameters(constructor)); + } + + private static Map parseParameters( + Constructor constructor) { + Map parameters = new LinkedHashMap<>(); + for (Parameter parameter : constructor.getParameters()) { + String name = parameter.getName(); + DefaultValue[] annotationsByType = parameter + .getAnnotationsByType(DefaultValue.class); + String[] defaultValue = (annotationsByType.length > 0) + ? annotationsByType[0].value() : null; + parameters.computeIfAbsent(name, + (key) -> new ConstructorParameter(name, + ResolvableType.forClass(parameter.getType()), + parameter.getDeclaredAnnotations(), defaultValue)); + } + return parameters; + } + + } + /** * A constructor parameter being bound. */ diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java index e58888660a0..d55bb45a064 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java @@ -174,18 +174,16 @@ class DefaultLogbackConfiguration { private DataSize getDataSize(String property, DataSize defaultSize) { String value = this.patterns.getProperty(property); - if (value != null) { - try { - return DataSize.parse(value); - } - catch (IllegalArgumentException ex) { - FileSize fileSize = FileSize.valueOf(value); - return DataSize.ofBytes(fileSize.getSize()); - } - } - else { + if (value == null) { return defaultSize; } + try { + return DataSize.parse(value); + } + catch (IllegalArgumentException ex) { + FileSize fileSize = FileSize.valueOf(value); + return DataSize.ofBytes(fileSize.getSize()); + } } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index 50c7ae9a659..5897dbd9af4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -240,8 +240,8 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { @Test public void springConfigLocations() { String[] locations = getSpringConfigLocations(this.loggingSystem); - assertThat(locations).isEqualTo( - new String[] { "log4j2-spring.properties", "log4j2-spring.xml" }); + assertThat(locations).containsExactly("log4j2-spring.properties", + "log4j2-spring.xml"); } @Test diff --git a/spring-boot-samples/spring-boot-sample-tomcat/src/main/java/sample/tomcat/web/SampleController.java b/spring-boot-samples/spring-boot-sample-tomcat/src/main/java/sample/tomcat/web/SampleController.java index d608fff1b88..1098b60acfd 100644 --- a/spring-boot-samples/spring-boot-sample-tomcat/src/main/java/sample/tomcat/web/SampleController.java +++ b/spring-boot-samples/spring-boot-sample-tomcat/src/main/java/sample/tomcat/web/SampleController.java @@ -20,8 +20,10 @@ import sample.tomcat.service.HelloWorldService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; @Controller public class SampleController { @@ -32,7 +34,12 @@ public class SampleController { @GetMapping("/") @ResponseBody public String helloWorld() { - return this.helloWorldService.getHelloMessage(); + throw new RuntimeException("Fail"); + } + + @ExceptionHandler(RuntimeException.class) + public ModelAndView handle(RuntimeException ex) { + return null; } } diff --git a/spring-boot-samples/spring-boot-sample-tomcat/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-tomcat/src/main/resources/application.properties index 4c0dadec6d3..3455c57ddf9 100644 --- a/spring-boot-samples/spring-boot-sample-tomcat/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-tomcat/src/main/resources/application.properties @@ -1,3 +1,5 @@ server.compression.enabled: true server.compression.min-response-size: 1 server.connection-timeout=5000 + +spring.mvc.log-resolved-exception=true