commit
0980362a88
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright 2012-2022 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.build.context.properties;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.SourceTask;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
/**
|
||||
* {@link SourceTask} that checks additional Spring configuration metadata files.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class CheckAdditionalSpringConfigurationMetadata extends SourceTask {
|
||||
|
||||
private final RegularFileProperty reportLocation;
|
||||
|
||||
public CheckAdditionalSpringConfigurationMetadata() {
|
||||
this.reportLocation = getProject().getObjects().fileProperty();
|
||||
}
|
||||
|
||||
@OutputFile
|
||||
public RegularFileProperty getReportLocation() {
|
||||
return this.reportLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@InputFiles
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
public FileTree getSource() {
|
||||
return super.getSource();
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void check() throws JsonParseException, IOException {
|
||||
Report report = createReport();
|
||||
File reportFile = getReportLocation().get().getAsFile();
|
||||
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
if (report.hasProblems()) {
|
||||
throw new GradleException(
|
||||
"Problems found in additional Spring configuration metadata. See " + reportFile + " for details.");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Report report = new Report();
|
||||
for (File file : getSource().getFiles()) {
|
||||
Analysis analysis = report.analysis(getProject().getProjectDir().toPath().relativize(file.toPath()));
|
||||
Map<String, Object> json = objectMapper.readValue(file, Map.class);
|
||||
check("groups", json, analysis);
|
||||
check("properties", json, analysis);
|
||||
check("hints", json, analysis);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void check(String key, Map<String, Object> json, Analysis analysis) {
|
||||
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.get(key);
|
||||
List<String> names = groups.stream().map((group) -> (String) group.get("name")).collect(Collectors.toList());
|
||||
List<String> sortedNames = sortedCopy(names);
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
String actual = names.get(i);
|
||||
String expected = sortedNames.get(i);
|
||||
if (!actual.equals(expected)) {
|
||||
analysis.problems.add("Wrong order at $." + key + "[" + i + "].name - expected '" + expected
|
||||
+ "' but found '" + actual + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> sortedCopy(Collection<String> original) {
|
||||
List<String> copy = new ArrayList<>(original);
|
||||
Collections.sort(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static final class Report implements Iterable<String> {
|
||||
|
||||
private final List<Analysis> analyses = new ArrayList<>();
|
||||
|
||||
private Analysis analysis(Path path) {
|
||||
Analysis analysis = new Analysis(path);
|
||||
this.analyses.add(analysis);
|
||||
return analysis;
|
||||
}
|
||||
|
||||
private boolean hasProblems() {
|
||||
for (Analysis analysis : this.analyses) {
|
||||
if (!analysis.problems.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
List<String> lines = new ArrayList<>();
|
||||
for (Analysis analysis : this.analyses) {
|
||||
lines.add(analysis.source.toString());
|
||||
lines.add("");
|
||||
if (analysis.problems.isEmpty()) {
|
||||
lines.add("No problems found.");
|
||||
}
|
||||
else {
|
||||
lines.addAll(analysis.problems);
|
||||
}
|
||||
lines.add("");
|
||||
}
|
||||
return lines.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class Analysis {
|
||||
|
||||
private final List<String> problems = new ArrayList<>();
|
||||
|
||||
private final Path source;
|
||||
|
||||
private Analysis(Path source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
|
@ -27,7 +27,9 @@ import org.gradle.api.plugins.JavaPlugin;
|
|||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
@ -41,6 +43,8 @@ import org.springframework.util.StringUtils;
|
|||
* argument.
|
||||
* <li>Adding the outputs of the processResources task as inputs of the compileJava task
|
||||
* to ensure that the additional metadata is available when the annotation processor runs.
|
||||
* <li>Registering a {@link CheckAdditionalSpringConfigurationMetadata} task and
|
||||
* configuring the {@code check} task to depend upon it.
|
||||
* <li>Defining an artifact for the resulting configuration property metadata so that it
|
||||
* can be consumed by downstream projects.
|
||||
* </ul>
|
||||
|
@ -55,11 +59,17 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
|
|||
*/
|
||||
public static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = "configurationPropertiesMetadata";
|
||||
|
||||
/**
|
||||
* Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.
|
||||
*/
|
||||
public static final String CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkAdditionalSpringConfigurationMetadata";
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
|
||||
addConfigurationProcessorDependency(project);
|
||||
configureAdditionalMetadataLocationsCompilerArgument(project);
|
||||
registerCheckAdditionalMetadataTask(project);
|
||||
addMetadataArtifact(project);
|
||||
});
|
||||
}
|
||||
|
@ -95,4 +105,20 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
|
|||
.stream().map(project.getRootProject()::relativePath).collect(Collectors.toSet())));
|
||||
}
|
||||
|
||||
private void registerCheckAdditionalMetadataTask(Project project) {
|
||||
TaskProvider<CheckAdditionalSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()
|
||||
.register(CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME,
|
||||
CheckAdditionalSpringConfigurationMetadata.class);
|
||||
checkConfigurationMetadata.configure((check) -> {
|
||||
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets()
|
||||
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
||||
check.setSource(mainSourceSet.getResources());
|
||||
check.include("META-INF/additional-spring-configuration-metadata.json");
|
||||
check.getReportLocation().set(project.getLayout().getBuildDirectory()
|
||||
.file("reports/additional-spring-configuration-metadata/check.txt"));
|
||||
});
|
||||
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME)
|
||||
.configure((check) -> check.dependsOn(checkConfigurationMetadata));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -181,6 +181,14 @@
|
|||
"name": "server.shutdown",
|
||||
"defaultValue": "immediate"
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.certificate",
|
||||
"description": "Path to a PEM-encoded SSL certificate file."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.certificate-private-key",
|
||||
"description": "Path to a PEM-encoded private key file for the SSL certificate."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.ciphers",
|
||||
"description": "Supported SSL ciphers."
|
||||
|
@ -227,6 +235,14 @@
|
|||
"description": "SSL protocol to use.",
|
||||
"defaultValue": "TLS"
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.trust-certificate",
|
||||
"description": "Path to a PEM-encoded SSL certificate authority file."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.trust-certificate-private-key",
|
||||
"description": "Path to a PEM-encoded private key file for the SSL certificate authority."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.trust-store",
|
||||
"description": "Trust store that holds SSL certificates."
|
||||
|
@ -243,22 +259,6 @@
|
|||
"name": "server.ssl.trust-store-type",
|
||||
"description": "Type of the trust store."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.certificate",
|
||||
"description": "Path to a PEM-encoded SSL certificate file."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.certificate-private-key",
|
||||
"description": "Path to a PEM-encoded private key file for the SSL certificate."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.trust-certificate",
|
||||
"description": "Path to a PEM-encoded SSL certificate authority file."
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.trust-certificate-private-key",
|
||||
"description": "Path to a PEM-encoded private key file for the SSL certificate authority."
|
||||
},
|
||||
{
|
||||
"name": "server.tomcat.max-http-post-size",
|
||||
"type": "org.springframework.util.unit.DataSize",
|
||||
|
@ -544,16 +544,16 @@
|
|||
"name": "spring.data.cassandra.connection.init-query-timeout",
|
||||
"defaultValue": "5s"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.cassandra.controlconnection.timeout",
|
||||
"defaultValue": "5s"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.cassandra.contact-points",
|
||||
"defaultValue": [
|
||||
"127.0.0.1:9042"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spring.data.cassandra.controlconnection.timeout",
|
||||
"defaultValue": "5s"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.cassandra.jmx-enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
|
@ -1170,15 +1170,6 @@
|
|||
"name": "spring.groovy.template.suffix",
|
||||
"defaultValue": ".tpl"
|
||||
},
|
||||
{
|
||||
"name": "spring.jpa.hibernate.use-new-id-generator-mappings",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is actually a shortcut for the \"hibernate.id.new_generator_mappings\" property. When not specified will default to \"true\".",
|
||||
"deprecation": {
|
||||
"level": "error",
|
||||
"reason": "Hibernate no longer supports disabling the use of new ID generator mappings."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.http.converters.preferred-json-mapper",
|
||||
"type": "java.lang.String",
|
||||
|
@ -1280,6 +1271,15 @@
|
|||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.jpa.hibernate.use-new-id-generator-mappings",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is actually a shortcut for the \"hibernate.id.new_generator_mappings\" property. When not specified will default to \"true\".",
|
||||
"deprecation": {
|
||||
"level": "error",
|
||||
"reason": "Hibernate no longer supports disabling the use of new ID generator mappings."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.jpa.open-in-view",
|
||||
"defaultValue": true
|
||||
|
|
Loading…
Reference in New Issue