Commit 2dfd916c authored by Phillip Webb's avatar Phillip Webb

Polish

parent dabe75a2
...@@ -103,13 +103,11 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration { ...@@ -103,13 +103,11 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension( public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(
GitProperties properties, ObjectProvider<InfoContributor> infoContributors) { GitProperties properties, ObjectProvider<InfoContributor> infoContributors) {
List<InfoContributor> contributors = infoContributors.orderedStream() List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> { .map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
if (infoContributor instanceof GitInfoContributor) { ? new GitInfoContributor(properties,
return new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL)
InfoPropertiesInfoContributor.Mode.FULL); : infoContributor)
} .collect(Collectors.toList());
return infoContributor;
}).collect(Collectors.toList());
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
} }
......
...@@ -104,13 +104,11 @@ public class CloudFoundryActuatorAutoConfiguration { ...@@ -104,13 +104,11 @@ public class CloudFoundryActuatorAutoConfiguration {
public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension( public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(
GitProperties properties, ObjectProvider<InfoContributor> infoContributors) { GitProperties properties, ObjectProvider<InfoContributor> infoContributors) {
List<InfoContributor> contributors = infoContributors.orderedStream() List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> { .map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
if (infoContributor instanceof GitInfoContributor) { ? new GitInfoContributor(properties,
return new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL)
InfoPropertiesInfoContributor.Mode.FULL); : infoContributor)
} .collect(Collectors.toList());
return infoContributor;
}).collect(Collectors.toList());
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
} }
......
...@@ -48,6 +48,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -48,6 +48,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.log.LogMessage;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus. * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus.
...@@ -142,7 +143,7 @@ public class PrometheusMetricsExportAutoConfiguration { ...@@ -142,7 +143,7 @@ public class PrometheusMetricsExportAutoConfiguration {
return new PushGateway(new URL(url)); return new PushGateway(new URL(url));
} }
catch (MalformedURLException ex) { catch (MalformedURLException ex) {
logger.warn(String.format( logger.warn(LogMessage.format(
"Invalid PushGateway base url '%s': update your configuration to a valid URL", "Invalid PushGateway base url '%s': update your configuration to a valid URL",
url)); url));
return new PushGateway(url); return new PushGateway(url);
......
...@@ -157,8 +157,8 @@ public class ManagementContextAutoConfiguration { ...@@ -157,8 +157,8 @@ public class ManagementContextAutoConfiguration {
AbstractApplicationContext context = (AbstractApplicationContext) this.applicationContext; AbstractApplicationContext context = (AbstractApplicationContext) this.applicationContext;
List<BeanFactoryPostProcessor> postProcessors = context List<BeanFactoryPostProcessor> postProcessors = context
.getBeanFactoryPostProcessors(); .getBeanFactoryPostProcessors();
return postProcessors.stream().anyMatch(( return postProcessors.stream().anyMatch(
postProcessor) -> postProcessor instanceof LazyInitializationBeanFactoryPostProcessor); LazyInitializationBeanFactoryPostProcessor.class::isInstance);
} }
private void setClassLoaderIfPossible(ConfigurableApplicationContext child) { private void setClassLoaderIfPossible(ConfigurableApplicationContext child) {
......
...@@ -56,7 +56,6 @@ public class ManagementContextAutoConfigurationTests { ...@@ -56,7 +56,6 @@ public class ManagementContextAutoConfigurationTests {
contextRunner.withPropertyValues("server.port=0", "management.server.port=0").run( contextRunner.withPropertyValues("server.port=0", "management.server.port=0").run(
(context) -> assertThat(tomcatStartedOccurencesIn(this.output.toString())) (context) -> assertThat(tomcatStartedOccurencesIn(this.output.toString()))
.isEqualTo(2)); .isEqualTo(2));
} }
private int tomcatStartedOccurencesIn(String output) { private int tomcatStartedOccurencesIn(String output) {
......
...@@ -91,7 +91,7 @@ public class HttpTraceWebFilter implements WebFilter, Ordered { ...@@ -91,7 +91,7 @@ public class HttpTraceWebFilter implements WebFilter, Ordered {
Principal principal, WebSession session) { Principal principal, WebSession session) {
ServerWebExchangeTraceableRequest request = new ServerWebExchangeTraceableRequest( ServerWebExchangeTraceableRequest request = new ServerWebExchangeTraceableRequest(
exchange); exchange);
final HttpTrace trace = this.tracer.receivedRequest(request); HttpTrace trace = this.tracer.receivedRequest(request);
exchange.getResponse().beforeCommit(() -> { exchange.getResponse().beforeCommit(() -> {
TraceableServerHttpResponse response = new TraceableServerHttpResponse( TraceableServerHttpResponse response = new TraceableServerHttpResponse(
exchange.getResponse()); exchange.getResponse());
......
...@@ -38,15 +38,12 @@ class FlywayMigrationScriptMissingFailureAnalyzer ...@@ -38,15 +38,12 @@ class FlywayMigrationScriptMissingFailureAnalyzer
.append("no migration scripts location is configured").toString(), .append("no migration scripts location is configured").toString(),
"Check your Flyway configuration", cause); "Check your Flyway configuration", cause);
} }
else { description.append(String.format(
description.append(String.format( "none of the following migration scripts locations could be found:%n%n"));
"none of the following migration scripts locations could be found:%n%n")); cause.getLocations().forEach(
cause.getLocations().forEach((location) -> description (location) -> description.append(String.format("\t- %s%n", location)));
.append(String.format("\t- %s%n", location))); return new FailureAnalysis(description.toString(),
return new FailureAnalysis(description.toString(), "Review the locations above or check your Flyway configuration", cause);
"Review the locations above or check your Flyway configuration",
cause);
}
} }
} }
...@@ -74,41 +74,44 @@ public class MongoReactiveAutoConfiguration { ...@@ -74,41 +74,44 @@ public class MongoReactiveAutoConfiguration {
return new NettyDriverMongoClientSettingsBuilderCustomizer(settings); return new NettyDriverMongoClientSettingsBuilderCustomizer(settings);
} }
private static final class NettyDriverMongoClientSettingsBuilderCustomizer }
implements MongoClientSettingsBuilderCustomizer, DisposableBean {
private final ObjectProvider<MongoClientSettings> settings; /**
* {@link MongoClientSettingsBuilderCustomizer} to apply Mongo client settings.
*/
private static final class NettyDriverMongoClientSettingsBuilderCustomizer
implements MongoClientSettingsBuilderCustomizer, DisposableBean {
private volatile EventLoopGroup eventLoopGroup; private final ObjectProvider<MongoClientSettings> settings;
private NettyDriverMongoClientSettingsBuilderCustomizer( private volatile EventLoopGroup eventLoopGroup;
ObjectProvider<MongoClientSettings> settings) {
this.settings = settings;
}
@Override private NettyDriverMongoClientSettingsBuilderCustomizer(
public void customize(Builder builder) { ObjectProvider<MongoClientSettings> settings) {
if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) { this.settings = settings;
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); }
this.eventLoopGroup = eventLoopGroup;
builder.streamFactoryFactory(NettyStreamFactoryFactory.builder()
.eventLoopGroup(eventLoopGroup).build());
}
}
@Override @Override
public void destroy() { public void customize(Builder builder) {
EventLoopGroup eventLoopGroup = this.eventLoopGroup; if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) {
if (eventLoopGroup != null) { NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
eventLoopGroup.shutdownGracefully().awaitUninterruptibly(); this.eventLoopGroup = eventLoopGroup;
this.eventLoopGroup = null; builder.streamFactoryFactory(NettyStreamFactoryFactory.builder()
} .eventLoopGroup(eventLoopGroup).build());
} }
}
private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) { @Override
return settings != null && settings.getStreamFactoryFactory() != null; 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;
} }
} }
......
...@@ -43,7 +43,7 @@ class RSocketNettyServerCustomizer implements NettyServerCustomizer { ...@@ -43,7 +43,7 @@ class RSocketNettyServerCustomizer implements NettyServerCustomizer {
@Override @Override
public HttpServer apply(HttpServer httpServer) { public HttpServer apply(HttpServer httpServer) {
final ServerTransport.ConnectionAcceptor acceptor = RSocketFactory.receive() ServerTransport.ConnectionAcceptor acceptor = RSocketFactory.receive()
.acceptor(this.messageHandlerAcceptor).toConnectionAcceptor(); .acceptor(this.messageHandlerAcceptor).toConnectionAcceptor();
return httpServer.route((routes) -> routes.ws(this.mappingPath, return httpServer.route((routes) -> routes.ws(this.mappingPath,
WebsocketRouteTransport.newHandler(acceptor))); WebsocketRouteTransport.newHandler(acceptor)));
......
...@@ -29,7 +29,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; ...@@ -29,7 +29,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.rsocket") @ConfigurationProperties("spring.rsocket")
public class RSocketProperties { public class RSocketProperties {
private Server server = new Server(); private final Server server = new Server();
public Server getServer() { public Server getServer() {
return this.server; return this.server;
......
...@@ -77,6 +77,8 @@ import org.springframework.web.context.support.GenericWebApplicationContext; ...@@ -77,6 +77,8 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
*/ */
public class SpringBootContextLoader extends AbstractContextLoader { public class SpringBootContextLoader extends AbstractContextLoader {
private static final String[] NO_ARGS = new String[0];
@Override @Override
public ApplicationContext loadContext(MergedContextConfiguration config) public ApplicationContext loadContext(MergedContextConfiguration config)
throws Exception { throws Exception {
...@@ -155,7 +157,7 @@ public class SpringBootContextLoader extends AbstractContextLoader { ...@@ -155,7 +157,7 @@ public class SpringBootContextLoader extends AbstractContextLoader {
protected String[] getArgs(MergedContextConfiguration config) { protected String[] getArgs(MergedContextConfiguration config) {
SpringBootTest annotation = AnnotatedElementUtils SpringBootTest annotation = AnnotatedElementUtils
.findMergedAnnotation(config.getTestClass(), SpringBootTest.class); .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, private void setActiveProfiles(ConfigurableEnvironment environment,
......
/*
* 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();
}
}
...@@ -27,29 +27,30 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope ...@@ -27,29 +27,30 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
* *
* @author Brian Clozel * @author Brian Clozel
*/ */
class CompoundKeyEntry extends AbstractConfigurationEntry { class CompoundConfigurationTableEntry extends ConfigurationTableEntry {
private Set<String> configurationKeys; private Set<String> configurationKeys;
private String description; private String description;
CompoundKeyEntry(String key, String description) { CompoundConfigurationTableEntry(String key, String description) {
this.key = key; this.key = key;
this.description = description; this.description = description;
this.configurationKeys = new TreeSet<>(); this.configurationKeys = new TreeSet<>();
} }
void addConfigurationKeys(ConfigurationMetadataProperty... properties) { void addConfigurationKeys(ConfigurationMetadataProperty... properties) {
Stream.of(properties) Stream.of(properties).map(ConfigurationMetadataProperty::getId)
.forEach((property) -> this.configurationKeys.add(property.getId())); .forEach(this.configurationKeys::add);
} }
@Override @Override
public void writeAsciidoc(StringBuilder builder) { public void write(AsciidocBuilder builder) {
builder.append("|`+++"); builder.append("|`+++");
this.configurationKeys.forEach((key) -> builder.append(key).append(NEWLINE)); this.configurationKeys.forEach(builder::appendln);
builder.append("+++`").append(NEWLINE).append("|").append(NEWLINE).append("|+++") builder.appendln("+++`");
.append(this.description).append("+++").append(NEWLINE); builder.appendln("|");
builder.appendln("|+++", this.description, "+++");
} }
} }
...@@ -29,7 +29,6 @@ import java.util.Map; ...@@ -29,7 +29,6 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
/** /**
...@@ -39,8 +38,21 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepos ...@@ -39,8 +38,21 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepos
*/ */
public class ConfigurationMetadataDocumentWriter { public class ConfigurationMetadataDocumentWriter {
public void writeDocument(Path outputDirPath, DocumentOptions options, public void writeDocument(Path outputDirectory, DocumentOptions options,
InputStream... metadataInput) throws IOException { InputStream... metadata) throws IOException {
assertValidOutputDirectory(outputDirectory);
if (!Files.exists(outputDirectory)) {
Files.createDirectory(outputDirectory);
}
assertMetadata(metadata);
List<ConfigurationTable> tables = createConfigTables(
getMetadataProperties(metadata), options);
for (ConfigurationTable table : tables) {
writeConfigurationTable(table, outputDirectory);
}
}
private void assertValidOutputDirectory(Path outputDirPath) {
if (outputDirPath == null) { if (outputDirPath == null) {
throw new IllegalArgumentException("output path should not be null"); throw new IllegalArgumentException("output path should not be null");
} }
...@@ -48,64 +60,33 @@ public class ConfigurationMetadataDocumentWriter { ...@@ -48,64 +60,33 @@ public class ConfigurationMetadataDocumentWriter {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"output path already exists and is not a directory"); "output path already exists and is not a directory");
} }
else if (!Files.exists(outputDirPath)) { }
Files.createDirectory(outputDirPath);
} private void assertMetadata(InputStream... metadata) {
if (metadataInput == null || metadataInput.length < 1) { if (metadata == null || metadata.length < 1) {
throw new IllegalArgumentException("missing input metadata"); throw new IllegalArgumentException("missing input metadata");
} }
}
ConfigurationMetadataRepository configRepository = ConfigurationMetadataRepositoryJsonBuilder private Map<String, ConfigurationMetadataProperty> getMetadataProperties(
.create(metadataInput).build(); InputStream... metadata) throws IOException {
Map<String, ConfigurationMetadataProperty> allProperties = configRepository ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder
.getAllProperties(); .create(metadata);
return builder.build().getAllProperties();
List<ConfigurationTable> 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 List<ConfigurationTable> createConfigTables( private List<ConfigurationTable> createConfigTables(
Map<String, ConfigurationMetadataProperty> allProperties, Map<String, ConfigurationMetadataProperty> metadataProperties,
DocumentOptions options) { DocumentOptions options) {
List<ConfigurationTable> tables = new ArrayList<>();
final List<ConfigurationTable> tables = new ArrayList<>(); List<String> unmappedKeys = metadataProperties.values().stream()
final List<String> unmappedKeys = allProperties.values().stream() .filter((property) -> !property.isDeprecated())
.filter((prop) -> !prop.isDeprecated()).map((prop) -> prop.getId()) .map(ConfigurationMetadataProperty::getId).collect(Collectors.toList());
.collect(Collectors.toList()); Map<String, CompoundConfigurationTableEntry> overrides = getOverrides(
metadataProperties, unmappedKeys, options);
final Map<String, CompoundKeyEntry> overrides = getOverrides(allProperties, options.getMetadataSections().forEach(
unmappedKeys, options); (id, keyPrefixes) -> tables.add(createConfigTable(metadataProperties,
unmappedKeys, overrides, id, keyPrefixes)));
options.getMetadataSections().forEach((id, keyPrefixes) -> {
ConfigurationTable table = new ConfigurationTable(id);
tables.add(table);
for (String keyPrefix : keyPrefixes) {
List<String> matchingOverrides = overrides.keySet().stream()
.filter((overrideKey) -> overrideKey.startsWith(keyPrefix))
.collect(Collectors.toList());
matchingOverrides
.forEach((match) -> table.addEntry(overrides.remove(match)));
}
List<String> 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);
});
if (!unmappedKeys.isEmpty()) { if (!unmappedKeys.isEmpty()) {
throw new IllegalStateException( throw new IllegalStateException(
"The following keys were not written to the documentation: " "The following keys were not written to the documentation: "
...@@ -116,22 +97,21 @@ public class ConfigurationMetadataDocumentWriter { ...@@ -116,22 +97,21 @@ public class ConfigurationMetadataDocumentWriter {
"The following keys were not written to the documentation: " "The following keys were not written to the documentation: "
+ String.join(", ", overrides.keySet())); + String.join(", ", overrides.keySet()));
} }
return tables; return tables;
} }
private Map<String, CompoundKeyEntry> getOverrides( private Map<String, CompoundConfigurationTableEntry> getOverrides(
Map<String, ConfigurationMetadataProperty> allProperties, Map<String, ConfigurationMetadataProperty> metadataProperties,
List<String> unmappedKeys, DocumentOptions options) { List<String> unmappedKeys, DocumentOptions options) {
final Map<String, CompoundKeyEntry> overrides = new HashMap<>(); Map<String, CompoundConfigurationTableEntry> overrides = new HashMap<>();
options.getOverrides().forEach((keyPrefix, description) -> { options.getOverrides().forEach((keyPrefix, description) -> {
final CompoundKeyEntry entry = new CompoundKeyEntry(keyPrefix, description); CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry(
keyPrefix, description);
List<String> matchingKeys = unmappedKeys.stream() List<String> matchingKeys = unmappedKeys.stream()
.filter((key) -> key.startsWith(keyPrefix)) .filter((key) -> key.startsWith(keyPrefix))
.collect(Collectors.toList()); .collect(Collectors.toList());
for (String matchingKey : matchingKeys) { for (String matchingKey : matchingKeys) {
entry.addConfigurationKeys(allProperties.get(matchingKey)); entry.addConfigurationKeys(metadataProperties.get(matchingKey));
} }
overrides.put(keyPrefix, entry); overrides.put(keyPrefix, entry);
unmappedKeys.removeAll(matchingKeys); unmappedKeys.removeAll(matchingKeys);
...@@ -139,4 +119,37 @@ public class ConfigurationMetadataDocumentWriter { ...@@ -139,4 +119,37 @@ public class ConfigurationMetadataDocumentWriter {
return overrides; return overrides;
} }
private ConfigurationTable createConfigTable(
Map<String, ConfigurationMetadataProperty> metadataProperties,
List<String> unmappedKeys,
Map<String, CompoundConfigurationTableEntry> overrides, String id,
List<String> keyPrefixes) {
ConfigurationTable table = new ConfigurationTable(id);
for (String keyPrefix : keyPrefixes) {
List<String> matchingOverrides = overrides.keySet().stream()
.filter((overrideKey) -> overrideKey.startsWith(keyPrefix))
.collect(Collectors.toList());
matchingOverrides.forEach((match) -> table.addEntry(overrides.remove(match)));
}
List<String> 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));
}
}
} }
...@@ -27,11 +27,9 @@ import java.util.TreeSet; ...@@ -27,11 +27,9 @@ import java.util.TreeSet;
*/ */
class ConfigurationTable { class ConfigurationTable {
private static final String NEWLINE = System.lineSeparator();
private final String id; private final String id;
private final Set<AbstractConfigurationEntry> entries; private final Set<ConfigurationTableEntry> entries;
ConfigurationTable(String id) { ConfigurationTable(String id) {
this.id = id; this.id = id;
...@@ -42,20 +40,21 @@ class ConfigurationTable { ...@@ -42,20 +40,21 @@ class ConfigurationTable {
return this.id; return this.id;
} }
void addEntry(AbstractConfigurationEntry... entries) { void addEntry(ConfigurationTableEntry... entries) {
this.entries.addAll(Arrays.asList(entries)); this.entries.addAll(Arrays.asList(entries));
} }
String toAsciidocTable() { String toAsciidocTable() {
final StringBuilder builder = new StringBuilder(); AsciidocBuilder builder = new AsciidocBuilder();
builder.append("[cols=\"1,1,2\", options=\"header\"]").append(NEWLINE); builder.appendln("[cols=\"1,1,2\", options=\"header\"]");
builder.append("|===").append(NEWLINE).append("|Key|Default Value|Description") builder.appendln("|===");
.append(NEWLINE).append(NEWLINE); builder.appendln("|Key|Default Value|Description");
builder.appendln();
this.entries.forEach((entry) -> { this.entries.forEach((entry) -> {
entry.writeAsciidoc(builder); entry.write(builder);
builder.append(NEWLINE); builder.appendln();
}); });
return builder.append("|===").append(NEWLINE).toString(); return builder.appendln("|===").toString();
} }
} }
...@@ -16,17 +16,12 @@ ...@@ -16,17 +16,12 @@
package org.springframework.boot.configurationdocs; package org.springframework.boot.configurationdocs;
import java.util.Objects;
/** /**
* Abstract class for entries in {@link ConfigurationTable}. * Abstract class for entries in {@link ConfigurationTable}.
* *
* @author Brian Clozel * @author Brian Clozel
*/ */
abstract class AbstractConfigurationEntry abstract class ConfigurationTableEntry implements Comparable<ConfigurationTableEntry> {
implements Comparable<AbstractConfigurationEntry> {
protected static final String NEWLINE = System.lineSeparator();
protected String key; protected String key;
...@@ -34,27 +29,27 @@ abstract class AbstractConfigurationEntry ...@@ -34,27 +29,27 @@ abstract class AbstractConfigurationEntry
return this.key; return this.key;
} }
public abstract void writeAsciidoc(StringBuilder builder); public abstract void write(AsciidocBuilder builder);
@Override @Override
public boolean equals(Object o) { public boolean equals(Object obj) {
if (this == o) { if (this == obj) {
return true; return true;
} }
if (o == null || getClass() != o.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
AbstractConfigurationEntry that = (AbstractConfigurationEntry) o; ConfigurationTableEntry other = (ConfigurationTableEntry) obj;
return this.key.equals(that.key); return this.key.equals(other.key);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(this.key); return this.key.hashCode();
} }
@Override @Override
public int compareTo(AbstractConfigurationEntry other) { public int compareTo(ConfigurationTableEntry other) {
return this.key.compareTo(other.getKey()); return this.key.compareTo(other.getKey());
} }
......
...@@ -26,58 +26,60 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope ...@@ -26,58 +26,60 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
* *
* @author Brian Clozel * @author Brian Clozel
*/ */
class SingleKeyEntry extends AbstractConfigurationEntry { class SingleConfigurationTableEntry extends ConfigurationTableEntry {
private String defaultValue; private final String description;
private String description; private final String defaultValue;
SingleKeyEntry(ConfigurationMetadataProperty property) {
SingleConfigurationTableEntry(ConfigurationMetadataProperty property) {
this.key = property.getId(); this.key = property.getId();
if (property.getType() != null if (property.getType() != null
&& property.getType().startsWith("java.util.Map")) { && property.getType().startsWith("java.util.Map")) {
this.key += ".*"; this.key += ".*";
} }
this.description = property.getDescription(); this.description = property.getDescription();
this.defaultValue = getDefaultValue(property.getDefaultValue());
}
if (property.getDefaultValue() != null) { private String getDefaultValue(Object defaultValue) {
if (property.getDefaultValue().getClass().isArray()) { if (defaultValue == null) {
this.defaultValue = Arrays.stream((Object[]) property.getDefaultValue()) return null;
.map(Object::toString).collect(Collectors.joining("," + NEWLINE)); }
} if (defaultValue.getClass().isArray()) {
else { return Arrays.stream((Object[]) defaultValue).map(Object::toString)
this.defaultValue = property.getDefaultValue().toString(); .collect(Collectors.joining("," + System.lineSeparator()));
}
} }
return defaultValue.toString();
} }
@Override @Override
public void writeAsciidoc(StringBuilder builder) { public void write(AsciidocBuilder builder) {
builder.append("|`+").append(this.key).append("+`").append(NEWLINE); builder.appendln("|`+", this.key, "+`");
String defaultValue = processDefaultValue(); writeDefaultValue(builder);
if (!defaultValue.isEmpty()) { writeDescription(builder);
builder.append("|`+").append(defaultValue).append("+`").append(NEWLINE); builder.appendln();
} }
else {
builder.append("|").append(NEWLINE); private void writeDefaultValue(AsciidocBuilder builder) {
} String defaultValue = (this.defaultValue != null) ? this.defaultValue : "";
if (this.description != null) { defaultValue = defaultValue.replace("\\", "\\\\").replace("|",
builder.append("|+++").append(this.description).append("+++"); "{vbar}" + System.lineSeparator());
if (defaultValue.isEmpty()) {
builder.appendln("|");
} }
else { else {
builder.append("|"); builder.appendln("|`+", defaultValue, "+`");
} }
builder.append(NEWLINE);
} }
private String processDefaultValue() { private void writeDescription(AsciidocBuilder builder) {
if (this.defaultValue != null && !this.defaultValue.isEmpty()) { if (this.description == null || this.description.isEmpty()) {
return this.defaultValue.replace("\\", "\\\\").replace("|", builder.append("|");
"{vbar}" + NEWLINE); }
else {
builder.append("|+++", this.description, "+++");
} }
return "";
} }
} }
...@@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope ...@@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link CompoundConfigurationTableEntry}.
*
* @author Brian Clozel * @author Brian Clozel
*/ */
public class CompoundKeyEntryTests { public class CompoundConfigurationTableEntryTests {
private static String NEWLINE = System.lineSeparator(); private static String NEWLINE = System.lineSeparator();
...@@ -34,21 +36,17 @@ public class CompoundKeyEntryTests { ...@@ -34,21 +36,17 @@ public class CompoundKeyEntryTests {
ConfigurationMetadataProperty firstProp = new ConfigurationMetadataProperty(); ConfigurationMetadataProperty firstProp = new ConfigurationMetadataProperty();
firstProp.setId("spring.test.first"); firstProp.setId("spring.test.first");
firstProp.setType("java.lang.String"); firstProp.setType("java.lang.String");
ConfigurationMetadataProperty secondProp = new ConfigurationMetadataProperty(); ConfigurationMetadataProperty secondProp = new ConfigurationMetadataProperty();
secondProp.setId("spring.test.second"); secondProp.setId("spring.test.second");
secondProp.setType("java.lang.String"); secondProp.setType("java.lang.String");
ConfigurationMetadataProperty thirdProp = new ConfigurationMetadataProperty(); ConfigurationMetadataProperty thirdProp = new ConfigurationMetadataProperty();
thirdProp.setId("spring.test.third"); thirdProp.setId("spring.test.third");
thirdProp.setType("java.lang.String"); thirdProp.setType("java.lang.String");
CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry(
CompoundKeyEntry entry = new CompoundKeyEntry("spring.test", "spring.test", "This is a description.");
"This is a description.");
entry.addConfigurationKeys(firstProp, secondProp, thirdProp); entry.addConfigurationKeys(firstProp, secondProp, thirdProp);
StringBuilder builder = new StringBuilder(); AsciidocBuilder builder = new AsciidocBuilder();
entry.writeAsciidoc(builder); entry.write(builder);
assertThat(builder.toString()).isEqualTo("|`+++spring.test.first" + NEWLINE assertThat(builder.toString()).isEqualTo("|`+++spring.test.first" + NEWLINE
+ "spring.test.second" + NEWLINE + "spring.test.third" + NEWLINE + "+++`" + "spring.test.second" + NEWLINE + "spring.test.third" + NEWLINE + "+++`"
+ NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE);
......
...@@ -23,6 +23,8 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope ...@@ -23,6 +23,8 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link ConfigurationTable}.
*
* @author Brian Clozel * @author Brian Clozel
*/ */
public class ConfigurationTableTests { public class ConfigurationTableTests {
...@@ -32,22 +34,18 @@ public class ConfigurationTableTests { ...@@ -32,22 +34,18 @@ public class ConfigurationTableTests {
@Test @Test
public void simpleTable() { public void simpleTable() {
ConfigurationTable table = new ConfigurationTable("test"); ConfigurationTable table = new ConfigurationTable("test");
ConfigurationMetadataProperty first = new ConfigurationMetadataProperty(); ConfigurationMetadataProperty first = new ConfigurationMetadataProperty();
first.setId("spring.test.prop"); first.setId("spring.test.prop");
first.setDefaultValue("something"); first.setDefaultValue("something");
first.setDescription("This is a description."); first.setDescription("This is a description.");
first.setType("java.lang.String"); first.setType("java.lang.String");
ConfigurationMetadataProperty second = new ConfigurationMetadataProperty(); ConfigurationMetadataProperty second = new ConfigurationMetadataProperty();
second.setId("spring.test.other"); second.setId("spring.test.other");
second.setDefaultValue("other value"); second.setDefaultValue("other value");
second.setDescription("This is another description."); second.setDescription("This is another description.");
second.setType("java.lang.String"); second.setType("java.lang.String");
table.addEntry(new SingleConfigurationTableEntry(first));
table.addEntry(new SingleKeyEntry(first)); table.addEntry(new SingleConfigurationTableEntry(second));
table.addEntry(new SingleKeyEntry(second));
assertThat(table.toAsciidocTable()) assertThat(table.toAsciidocTable())
.isEqualTo("[cols=\"1,1,2\", options=\"header\"]" + NEWLINE + "|===" .isEqualTo("[cols=\"1,1,2\", options=\"header\"]" + NEWLINE + "|==="
+ NEWLINE + "|Key|Default Value|Description" + NEWLINE + NEWLINE + NEWLINE + "|Key|Default Value|Description" + NEWLINE + NEWLINE
......
...@@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope ...@@ -23,9 +23,11 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link SingleConfigurationTableEntry}.
*
* @author Brian Clozel * @author Brian Clozel
*/ */
public class SingleKeyEntryTests { public class SingleConfigurationTableEntryTests {
private static String NEWLINE = System.lineSeparator(); private static String NEWLINE = System.lineSeparator();
...@@ -36,11 +38,9 @@ public class SingleKeyEntryTests { ...@@ -36,11 +38,9 @@ public class SingleKeyEntryTests {
property.setDefaultValue("something"); property.setDefaultValue("something");
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.lang.String"); property.setType("java.lang.String");
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE
+ "|`+something+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); + "|`+something+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE);
} }
...@@ -51,11 +51,9 @@ public class SingleKeyEntryTests { ...@@ -51,11 +51,9 @@ public class SingleKeyEntryTests {
property.setId("spring.test.prop"); property.setId("spring.test.prop");
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.lang.String"); property.setType("java.lang.String");
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|" assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE); + NEWLINE + "|+++This is a description.+++" + NEWLINE);
} }
...@@ -67,11 +65,9 @@ public class SingleKeyEntryTests { ...@@ -67,11 +65,9 @@ public class SingleKeyEntryTests {
property.setDefaultValue("first|second"); property.setDefaultValue("first|second");
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.lang.String"); property.setType("java.lang.String");
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE
+ "|`+first{vbar}" + NEWLINE + "second+`" + NEWLINE + "|`+first{vbar}" + NEWLINE + "second+`" + NEWLINE
+ "|+++This is a description.+++" + NEWLINE); + "|+++This is a description.+++" + NEWLINE);
...@@ -84,11 +80,9 @@ public class SingleKeyEntryTests { ...@@ -84,11 +80,9 @@ public class SingleKeyEntryTests {
property.setDefaultValue("first\\second"); property.setDefaultValue("first\\second");
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.lang.String"); property.setType("java.lang.String");
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()) assertThat(builder.toString())
.isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+first\\\\second+`" .isEqualTo("|`+spring.test.prop+`" + NEWLINE + "|`+first\\\\second+`"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE); + NEWLINE + "|+++This is a description.+++" + NEWLINE);
...@@ -100,11 +94,9 @@ public class SingleKeyEntryTests { ...@@ -100,11 +94,9 @@ public class SingleKeyEntryTests {
property.setId("spring.test.prop"); property.setId("spring.test.prop");
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.util.Map<java.lang.String,java.lang.String>"); property.setType("java.util.Map<java.lang.String,java.lang.String>");
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()).isEqualTo("|`+spring.test.prop.*+`" + NEWLINE + "|" assertThat(builder.toString()).isEqualTo("|`+spring.test.prop.*+`" + NEWLINE + "|"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE); + NEWLINE + "|+++This is a description.+++" + NEWLINE);
} }
...@@ -117,11 +109,9 @@ public class SingleKeyEntryTests { ...@@ -117,11 +109,9 @@ public class SingleKeyEntryTests {
property.setDescription("This is a description."); property.setDescription("This is a description.");
property.setType("java.util.List<java.lang.String>"); property.setType("java.util.List<java.lang.String>");
property.setDefaultValue(defaultValue); property.setDefaultValue(defaultValue);
SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property);
SingleKeyEntry entry = new SingleKeyEntry(property); AsciidocBuilder builder = new AsciidocBuilder();
StringBuilder builder = new StringBuilder(); entry.write(builder);
entry.writeAsciidoc(builder);
assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE assertThat(builder.toString()).isEqualTo("|`+spring.test.prop+`" + NEWLINE
+ "|`+first," + NEWLINE + "second," + NEWLINE + "third+`" + NEWLINE + "|`+first," + NEWLINE + "second," + NEWLINE + "third+`" + NEWLINE
+ "|+++This is a description.+++" + NEWLINE); + "|+++This is a description.+++" + NEWLINE);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.boot.configurationprocessor; package org.springframework.boot.configurationprocessor;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
...@@ -61,30 +62,36 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable ...@@ -61,30 +62,36 @@ class ConstructorParameterPropertyDescriptor extends PropertyDescriptor<Variable
private Object getDefaultValueFromAnnotation( private Object getDefaultValueFromAnnotation(
MetadataGenerationEnvironment environment, Element element) { MetadataGenerationEnvironment environment, Element element) {
AnnotationMirror defaultValueAnnotation = environment AnnotationMirror annotation = environment.getDefaultValueAnnotation(element);
.getDefaultValueAnnotation(element); List<String> defaultValue = getDefaultValue(environment, annotation);
if (defaultValueAnnotation != null) { if (defaultValue != null) {
List<String> defaultValue = (List<String>) environment try {
.getAnnotationElementValues(defaultValueAnnotation).get("value"); TypeMirror specificType = determineSpecificType(environment);
if (defaultValue != null) { if (defaultValue.size() == 1) {
try { return coerceValue(specificType, defaultValue.get(0));
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);
} }
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; return null;
} }
@SuppressWarnings("unchecked")
private List<String> getDefaultValue(MetadataGenerationEnvironment environment,
AnnotationMirror annotation) {
if (annotation == null) {
return null;
}
Map<String, Object> values = environment.getAnnotationElementValues(annotation);
return (List<String>) values.get("value");
}
private TypeMirror determineSpecificType(MetadataGenerationEnvironment environment) { private TypeMirror determineSpecificType(MetadataGenerationEnvironment environment) {
TypeMirror candidate = getSource().asType(); TypeMirror candidate = getSource().asType();
TypeMirror elementCandidate = environment.getTypeUtils() TypeMirror elementCandidate = environment.getTypeUtils()
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.boot.configurationprocessor; package org.springframework.boot.configurationprocessor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
...@@ -49,7 +50,24 @@ class MetadataGenerationEnvironment { ...@@ -49,7 +50,24 @@ class MetadataGenerationEnvironment {
private static final String NULLABLE_ANNOTATION = "org.springframework.lang.Nullable"; private static final String NULLABLE_ANNOTATION = "org.springframework.lang.Nullable";
private final Set<String> typeExcludes; private static final Set<String> TYPE_EXCLUDES;
static {
Set<String> 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; private final TypeUtils typeUtils;
...@@ -79,7 +97,6 @@ class MetadataGenerationEnvironment { ...@@ -79,7 +97,6 @@ class MetadataGenerationEnvironment {
String deprecatedConfigurationPropertyAnnotation, String deprecatedConfigurationPropertyAnnotation,
String defaultValueAnnotation, String endpointAnnotation, String defaultValueAnnotation, String endpointAnnotation,
String readOperationAnnotation) { String readOperationAnnotation) {
this.typeExcludes = determineTypeExcludes();
this.typeUtils = new TypeUtils(environment); this.typeUtils = new TypeUtils(environment);
this.elements = environment.getElementUtils(); this.elements = environment.getElementUtils();
this.messager = environment.getMessager(); this.messager = environment.getMessager();
...@@ -92,24 +109,6 @@ class MetadataGenerationEnvironment { ...@@ -92,24 +109,6 @@ class MetadataGenerationEnvironment {
this.readOperationAnnotation = readOperationAnnotation; this.readOperationAnnotation = readOperationAnnotation;
} }
private static Set<String> determineTypeExcludes() {
Set<String> 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) { private static FieldValuesParser resolveFieldValuesParser(ProcessingEnvironment env) {
try { try {
return new JavaCompilerFieldValuesParser(env); return new JavaCompilerFieldValuesParser(env);
...@@ -147,7 +146,7 @@ class MetadataGenerationEnvironment { ...@@ -147,7 +146,7 @@ class MetadataGenerationEnvironment {
if (typeName.endsWith("[]")) { if (typeName.endsWith("[]")) {
typeName = typeName.substring(0, typeName.length() - 2); typeName = typeName.substring(0, typeName.length() - 2);
} }
return this.typeExcludes.contains(typeName); return TYPE_EXCLUDES.contains(typeName);
} }
public boolean isDeprecated(Element element) { public boolean isDeprecated(Element element) {
......
...@@ -164,9 +164,8 @@ class TypeUtils { ...@@ -164,9 +164,8 @@ class TypeUtils {
return this.types.getDeclaredType(this.env.getElementUtils() return this.types.getDeclaredType(this.env.getElementUtils()
.getTypeElement(Object.class.getName())); .getTypeElement(Object.class.getName()));
} }
else { // return type argument to Collection<...> // return type argument to Collection<...>
return declaredType.getTypeArguments().get(0); return declaredType.getTypeArguments().get(0);
}
} }
// recursively walk the supertypes, looking for Collection<...> // recursively walk the supertypes, looking for Collection<...>
......
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
package org.springframework.boot.cloud; package org.springframework.boot.cloud;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment; 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.core.env.StandardEnvironment;
import org.springframework.util.StringUtils;
/** /**
* Simple detection for well known cloud platforms. For more advanced cloud provider * Simple detection for well known cloud platforms. For more advanced cloud provider
...@@ -73,27 +73,42 @@ public enum CloudPlatform { ...@@ -73,27 +73,42 @@ public enum CloudPlatform {
* Kubernetes platform. * Kubernetes platform.
*/ */
KUBERNETES { KUBERNETES {
private static final String SERVICE_HOST_SUFFIX = "_SERVICE_HOST";
private static final String SERVICE_PORT_SUFFIX = "_SERVICE_PORT";
@Override @Override
public boolean isActive(Environment environment) { public boolean isActive(Environment environment) {
if (environment instanceof ConfigurableEnvironment) { if (environment instanceof ConfigurableEnvironment) {
MapPropertySource propertySource = (MapPropertySource) ((ConfigurableEnvironment) environment) return isActive((ConfigurableEnvironment) environment);
.getPropertySources() }
.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); return false;
if (propertySource != null) { }
for (String name : propertySource.getPropertyNames()) {
if (name.endsWith("_SERVICE_HOST")) { private boolean isActive(ConfigurableEnvironment environment) {
String serviceName = StringUtils.split(name, PropertySource<?> environmentPropertySource = environment.getPropertySources()
"_SERVICE_HOST")[0]; .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
if (propertySource if (environmentPropertySource instanceof EnumerablePropertySource) {
.getProperty(serviceName + "_SERVICE_PORT") != null) { return isActive((EnumerablePropertySource<?>) environmentPropertySource);
return true; }
} 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; return false;
} }
}; };
/** /**
......
...@@ -116,6 +116,9 @@ public class ConfigFileApplicationListener ...@@ -116,6 +116,9 @@ public class ConfigFileApplicationListener
private static final Bindable<String[]> STRING_ARRAY = Bindable.of(String[].class); private static final Bindable<String[]> STRING_ARRAY = Bindable.of(String[].class);
private static final Bindable<List<String>> STRING_LIST = Bindable
.listOf(String.class);
/** /**
* The "active profiles" property name. * The "active profiles" property name.
*/ */
...@@ -701,18 +704,6 @@ public class ConfigFileApplicationListener ...@@ -701,18 +704,6 @@ public class ConfigFileApplicationListener
return new LinkedHashSet<>(list); 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<Profile> processedProfiles) {
String[] names = processedProfiles.stream()
.filter((profile) -> profile != null && !profile.isDefaultProfile())
.map(Profile::getName).toArray(String[]::new);
this.environment.setActiveProfiles(names);
}
private void addLoadedPropertySources() { private void addLoadedPropertySources() {
MutablePropertySources destination = this.environment.getPropertySources(); MutablePropertySources destination = this.environment.getPropertySources();
List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values()); List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
...@@ -773,8 +764,7 @@ public class ConfigFileApplicationListener ...@@ -773,8 +764,7 @@ public class ConfigFileApplicationListener
} }
private List<String> getDefaultProfiles(Binder binder, String property) { private List<String> getDefaultProfiles(Binder binder, String property) {
return Arrays return binder.bind(property, STRING_LIST).orElse(Collections.emptyList());
.asList(binder.bind(property, STRING_ARRAY).orElse(new String[] {}));
} }
} }
......
...@@ -91,11 +91,9 @@ final class ConfigurationPropertiesBeanDefinitionRegistrar { ...@@ -91,11 +91,9 @@ final class ConfigurationPropertiesBeanDefinitionRegistrar {
if (canBindAtCreationTime(type)) { if (canBindAtCreationTime(type)) {
return ConfigurationPropertiesBeanDefinition.from(beanFactory, name, type); return ConfigurationPropertiesBeanDefinition.from(beanFactory, name, type);
} }
else { GenericBeanDefinition definition = new GenericBeanDefinition();
GenericBeanDefinition definition = new GenericBeanDefinition(); definition.setBeanClass(type);
definition.setBeanClass(type); return definition;
return definition;
}
} }
private static boolean canBindAtCreationTime(Class<?> type) { private static boolean canBindAtCreationTime(Class<?> type) {
......
...@@ -72,18 +72,24 @@ class ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegist ...@@ -72,18 +72,24 @@ class ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegist
scanner.addIncludeFilter(new AnnotationTypeFilter(ConfigurationProperties.class)); scanner.addIncludeFilter(new AnnotationTypeFilter(ConfigurationProperties.class));
for (String basePackage : packages) { for (String basePackage : packages) {
if (StringUtils.hasText(basePackage)) { if (StringUtils.hasText(basePackage)) {
for (BeanDefinition candidate : scanner scan(beanFactory, registry, scanner, basePackage);
.findCandidateComponents(basePackage)) { }
String beanClassName = candidate.getBeanClassName(); }
try { }
Class<?> type = ClassUtils.forName(beanClassName, null);
ConfigurationPropertiesBeanDefinitionRegistrar.register(registry, private void scan(ConfigurableListableBeanFactory beanFactory,
beanFactory, type); BeanDefinitionRegistry registry,
} ClassPathScanningCandidateComponentProvider scanner, String basePackage)
catch (ClassNotFoundException ex) { throws LinkageError {
// Ignore 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
} }
} }
} }
......
...@@ -77,9 +77,8 @@ class EnableConfigurationPropertiesImportSelector implements ImportSelector { ...@@ -77,9 +77,8 @@ class EnableConfigurationPropertiesImportSelector implements ImportSelector {
} }
private List<Class<?>> collectClasses(List<?> values) { private List<Class<?>> collectClasses(List<?> values) {
return values.stream().flatMap((value) -> Arrays.stream((Object[]) value)) return values.stream().flatMap((value) -> Arrays.stream((Class<?>[]) value))
.map((o) -> (Class<?>) o).filter((type) -> void.class != type) .filter((type) -> void.class != type).collect(Collectors.toList());
.collect(Collectors.toList());
} }
} }
......
...@@ -21,6 +21,7 @@ import java.lang.reflect.Modifier; ...@@ -21,6 +21,7 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -58,30 +59,25 @@ class ConstructorParametersBinder implements BeanBinder { ...@@ -58,30 +59,25 @@ class ConstructorParametersBinder implements BeanBinder {
private List<Object> bind(BeanPropertyBinder propertyBinder, Bean bean, private List<Object> bind(BeanPropertyBinder propertyBinder, Bean bean,
BindConverter converter) { BindConverter converter) {
List<Object> boundParams = new ArrayList<>(); Collection<ConstructorParameter> parameters = bean.getParameters().values();
for (ConstructorParameter parameter : bean.getParameters().values()) { List<Object> boundParameters = new ArrayList<>(parameters.size());
Object bound = bind(parameter, propertyBinder); for (ConstructorParameter parameter : parameters) {
if (bound == null) { Object boundParameter = bind(parameter, propertyBinder);
bound = getDefaultValue(parameter, converter); if (boundParameter == null) {
boundParameter = getDefaultValue(parameter, converter);
} }
boundParams.add(bound); boundParameters.add(boundParameter);
} }
return boundParams; return boundParameters;
} }
private Object getDefaultValue(ConstructorParameter parameter, private Object getDefaultValue(ConstructorParameter parameter,
BindConverter converter) { BindConverter converter) {
if (parameter.getDefaultValue() != null) { if (parameter.getDefaultValue() == null) {
return converter.convert(parameter.getDefaultValue(), parameter.getType(), return null;
parameter.getAnnotations());
}
else {
Class<?> resolve = parameter.getType().resolve();
if (resolve != null && resolve.isPrimitive()) {
return null;
}
} }
return null; return converter.convert(parameter.getDefaultValue(), parameter.getType(),
parameter.getAnnotations());
} }
private Object bind(ConstructorParameter parameter, private Object bind(ConstructorParameter parameter,
...@@ -112,20 +108,9 @@ class ConstructorParametersBinder implements BeanBinder { ...@@ -112,20 +108,9 @@ class ConstructorParametersBinder implements BeanBinder {
return null; return null;
} }
if (KOTLIN_PRESENT && KotlinDetector.isKotlinType(type)) { if (KOTLIN_PRESENT && KotlinDetector.isKotlinType(type)) {
Constructor<?> primaryConstructor = BeanUtils return KotlinBeanProvider.get(type);
.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 null; return SimpleBeanProvider.get(type);
} }
public Map<String, ConstructorParameter> getParameters() { public Map<String, ConstructorParameter> getParameters() {
...@@ -138,49 +123,28 @@ class ConstructorParametersBinder implements BeanBinder { ...@@ -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<String, ConstructorParameter> parseParameters(
Constructor<?> constructor) {
Map<String, ConstructorParameter> 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 * A bean provider for a Kotlin class. Uses the Kotlin constructor to extract the
* parameter names. * parameter names.
*/ */
private static class KotlinBeanProvider { 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 KFunction<?> kotlinConstructor = ReflectJvmMapping
.getKotlinFunction(constructor); .getKotlinFunction(constructor);
if (kotlinConstructor != null) { if (kotlinConstructor != null) {
return new Bean(constructor, parseParameters(kotlinConstructor)); return new Bean(constructor, parseParameters(kotlinConstructor));
} }
else { return SimpleBeanProvider.get(constructor);
return SimpleBeanProvider.get(constructor);
}
} }
private static Map<String, ConstructorParameter> parseParameters( private static Map<String, ConstructorParameter> parseParameters(
...@@ -199,6 +163,42 @@ class ConstructorParametersBinder implements BeanBinder { ...@@ -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<String, ConstructorParameter> parseParameters(
Constructor<?> constructor) {
Map<String, ConstructorParameter> 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. * A constructor parameter being bound.
*/ */
......
...@@ -174,18 +174,16 @@ class DefaultLogbackConfiguration { ...@@ -174,18 +174,16 @@ class DefaultLogbackConfiguration {
private DataSize getDataSize(String property, DataSize defaultSize) { private DataSize getDataSize(String property, DataSize defaultSize) {
String value = this.patterns.getProperty(property); String value = this.patterns.getProperty(property);
if (value != null) { if (value == null) {
try {
return DataSize.parse(value);
}
catch (IllegalArgumentException ex) {
FileSize fileSize = FileSize.valueOf(value);
return DataSize.ofBytes(fileSize.getSize());
}
}
else {
return defaultSize; return defaultSize;
} }
try {
return DataSize.parse(value);
}
catch (IllegalArgumentException ex) {
FileSize fileSize = FileSize.valueOf(value);
return DataSize.ofBytes(fileSize.getSize());
}
} }
} }
...@@ -240,8 +240,8 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { ...@@ -240,8 +240,8 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test @Test
public void springConfigLocations() { public void springConfigLocations() {
String[] locations = getSpringConfigLocations(this.loggingSystem); String[] locations = getSpringConfigLocations(this.loggingSystem);
assertThat(locations).isEqualTo( assertThat(locations).containsExactly("log4j2-spring.properties",
new String[] { "log4j2-spring.properties", "log4j2-spring.xml" }); "log4j2-spring.xml");
} }
@Test @Test
......
...@@ -20,8 +20,10 @@ import sample.tomcat.service.HelloWorldService; ...@@ -20,8 +20,10 @@ import sample.tomcat.service.HelloWorldService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; 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.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller @Controller
public class SampleController { public class SampleController {
...@@ -32,7 +34,12 @@ public class SampleController { ...@@ -32,7 +34,12 @@ public class SampleController {
@GetMapping("/") @GetMapping("/")
@ResponseBody @ResponseBody
public String helloWorld() { public String helloWorld() {
return this.helloWorldService.getHelloMessage(); throw new RuntimeException("Fail");
}
@ExceptionHandler(RuntimeException.class)
public ModelAndView handle(RuntimeException ex) {
return null;
} }
} }
server.compression.enabled: true server.compression.enabled: true
server.compression.min-response-size: 1 server.compression.min-response-size: 1
server.connection-timeout=5000 server.connection-timeout=5000
spring.mvc.log-resolved-exception=true
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment