Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions initializr-docs/src/main/asciidoc/configuration-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ requires you to add a certain plugin to the build, you can provide a `BuildCusto
that adds the plugin and the customizer will be called according to the order specified on
it.

Similarly, an `ApplicationPropertiesCustomizer` can contribute properties to the
configuration files of the generated project, that is `application.properties` or
`application.yaml` depending on the requested `ConfigurationFileFormat`. Properties added
directly belong to the main source set and the default profile, `file` and `profile`
address the other source sets and Spring profiles. Each combination is written to
+src/{sourceSet}/resources/application[-{profile}]+, with the extension of the requested
format. Combinations without properties are skipped, except for the main source set and
the default profile, which is always written:

[source,java,indent=0]
----
include::{code-examples}/doc/generator/project/ProjectCustomizationExamples.java[tag=application-properties-customizer]
----



[[initializr-generator-spring-requirements]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.spring.initializr.doc.generator.project;

import io.spring.initializr.generator.buildsystem.SourceSet;
import io.spring.initializr.generator.buildsystem.gradle.GradleBuild;
import io.spring.initializr.generator.buildsystem.gradle.GradleBuildSystem;
import io.spring.initializr.generator.condition.ConditionalOnBuildSystem;
Expand All @@ -25,13 +26,16 @@
import io.spring.initializr.generator.project.ProjectDescriptionCustomizer;
import io.spring.initializr.generator.project.ProjectDescriptionField;
import io.spring.initializr.generator.spring.build.BuildCustomizer;
import io.spring.initializr.generator.spring.properties.ApplicationPropertiesCustomizer;

import org.springframework.context.annotation.Bean;

/**
* Examples of customizers.
*
* @author Stephane Nicoll
* @author Moritz Halbritter
* @author Denis A. Altoé Falqueto
*/
public class ProjectCustomizationExamples {

Expand Down Expand Up @@ -69,4 +73,18 @@ private boolean isBelowJava17(String jvmVersion) {
}
// end::jvm-version-change-reason[]

// tag::application-properties-customizer[]
@Bean
public ApplicationPropertiesCustomizer applicationPropertiesCustomizer() {
return (properties) -> {
// src/main/resources/application.properties (or .yaml)
properties.add("spring.application.name", "acme");
// src/test/resources/application.properties (or .yaml)
properties.file(SourceSet.TEST).add("spring.datasource.url", "jdbc:h2:mem:acme");
// src/main/resources/application-dev.properties (or .yaml)
properties.profile("dev").add("logging.level.root", "DEBUG");
};
}
// end::application-properties-customizer[]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2012 - present 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 io.spring.initializr.generator.spring.properties;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Map;

import io.spring.initializr.generator.buildsystem.BuildSystem;
import io.spring.initializr.generator.buildsystem.SourceSet;
import io.spring.initializr.generator.configuration.format.ConfigurationFileFormat;
import io.spring.initializr.generator.language.Language;
import io.spring.initializr.generator.language.SourceStructure;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.contributor.ProjectContributor;

import org.springframework.util.Assert;

/**
* Base {@link ProjectContributor} that writes the application configuration files of a
* project, one per {@link ApplicationPropertiesFile} that has properties. The default
* file of the main source set is written even when empty.
*
* @author Denis A. Altoé Falqueto
* @author Moritz Halbritter
* @see ApplicationProperties
*/
abstract class AbstractApplicationPropertiesContributor implements ProjectContributor {

private final ApplicationProperties properties;

private final ProjectDescription description;

private final ConfigurationFileFormat format;

/**
* Creates a new instance.
* @param properties the application properties to contribute
* @param description the description of the project, used to resolve the source
* structures
* @param format the format of the written files, defining their extension
*/
protected AbstractApplicationPropertiesContributor(ApplicationProperties properties, ProjectDescription description,
ConfigurationFileFormat format) {
this.properties = properties;
this.description = description;
this.format = format;
}

@Override
public void contribute(Path projectRoot) throws IOException {
BuildSystem buildSystem = this.description.getBuildSystem();
Assert.state(buildSystem != null, "'buildSystem' must not be null");
Language language = this.description.getLanguage();
Assert.state(language != null, "'language' must not be null");
for (SourceSet sourceSet : SourceSet.values()) {
contribute(buildSystem.getSource(projectRoot, language, sourceSet), sourceSet);
}
}

private void contribute(SourceStructure sourceStructure, SourceSet sourceSet) throws IOException {
for (Map.Entry<ProfileName, ApplicationPropertiesFile> entry : this.properties.files(sourceSet).entrySet()) {
ProfileName profile = entry.getKey();
ApplicationPropertiesFile file = entry.getValue();
// Generated projects always ship a main application file, even an empty one.
// Every other file is written only if it has properties.
boolean mainDefault = (sourceSet == SourceSet.MAIN) && ProfileName.DEFAULT.equals(profile);
if (file.isEmpty() && !mainDefault) {
continue;
}
writeFile(sourceStructure, profile, file);
}
}

private void writeFile(SourceStructure sourceStructure, ProfileName profile, ApplicationPropertiesFile file)
throws IOException {
Path output = resolveOutputFile(sourceStructure, profile);
if (!Files.exists(output)) {
Files.createDirectories(output.getParent());
Files.createFile(output);
}
try (PrintWriter writer = new PrintWriter(Files.newOutputStream(output, StandardOpenOption.APPEND), false,
StandardCharsets.UTF_8)) {
writeProperties(file.properties(), writer);
}
}

/**
* Writes the given properties in the format of this contributor.
* @param properties the properties to write, keyed by their dotted name
* @param writer the writer to use
*/
protected abstract void writeProperties(Map<String, Object> properties, PrintWriter writer);

private Path resolveOutputFile(SourceStructure sourceStructure, ProfileName profile) {
String fileName = "application" + profile.fileSuffix() + this.format.fileExtension();
return sourceStructure.getResourcesDirectory().resolve(fileName);
}

}
Loading