Skip to content

Commit 1ccd8da

Browse files
dreis2211wilkinsona
authored andcommitted
Allow the project to be built with Java 16
See gh-25171
1 parent 181d0ee commit 1ccd8da

File tree

9 files changed

+209
-24
lines changed

9 files changed

+209
-24
lines changed

buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616

1717
package org.springframework.boot.build;
1818

19-
import java.io.File;
2019
import java.util.Arrays;
2120
import java.util.Collections;
2221
import java.util.List;
2322
import java.util.Map;
2423
import java.util.Set;
2524
import java.util.TreeMap;
26-
import java.util.function.Consumer;
2725
import java.util.stream.Collectors;
2826

2927
import io.spring.javaformat.gradle.FormatTask;
@@ -49,6 +47,7 @@
4947

5048
import org.springframework.boot.build.optional.OptionalDependenciesPlugin;
5149
import org.springframework.boot.build.testing.TestFailuresPlugin;
50+
import org.springframework.boot.build.toolchain.ToolchainPlugin;
5251

5352
/**
5453
* Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the
@@ -103,6 +102,7 @@ void apply(Project project) {
103102
configureTestConventions(project);
104103
configureJarManifestConventions(project);
105104
configureDependencyManagement(project);
105+
configureToolchain(project);
106106
});
107107
}
108108

@@ -145,7 +145,6 @@ private String determineImplementationTitle(Project project, Set<String> sourceJ
145145

146146
private void configureTestConventions(Project project) {
147147
project.getTasks().withType(Test.class, (test) -> {
148-
withOptionalBuildJavaHome(project, (javaHome) -> test.setExecutable(javaHome + "/bin/java"));
149148
test.useJUnitPlatform();
150149
test.setMaxHeapSize("1024M");
151150
});
@@ -165,38 +164,25 @@ private boolean isCi() {
165164
}
166165

167166
private void configureJavadocConventions(Project project) {
168-
project.getTasks().withType(Javadoc.class, (javadoc) -> {
169-
javadoc.getOptions().source("1.8").encoding("UTF-8");
170-
withOptionalBuildJavaHome(project, (javaHome) -> javadoc.setExecutable(javaHome + "/bin/javadoc"));
171-
});
167+
project.getTasks().withType(Javadoc.class, (javadoc) -> javadoc.getOptions().source("1.8").encoding("UTF-8"));
172168
}
173169

174170
private void configureJavaCompileConventions(Project project) {
175171
project.getTasks().withType(JavaCompile.class, (compile) -> {
176172
compile.getOptions().setEncoding("UTF-8");
177-
withOptionalBuildJavaHome(project, (javaHome) -> {
178-
compile.getOptions().setFork(true);
179-
compile.getOptions().getForkOptions().setJavaHome(new File(javaHome));
180-
compile.getOptions().getForkOptions().setExecutable(javaHome + "/bin/javac");
181-
});
173+
compile.setSourceCompatibility("1.8");
174+
compile.setTargetCompatibility("1.8");
182175
List<String> args = compile.getOptions().getCompilerArgs();
183176
if (!args.contains("-parameters")) {
184177
args.add("-parameters");
185178
}
186-
if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
179+
if (!project.hasProperty("toolchainVersion") && JavaVersion.current() == JavaVersion.VERSION_1_8) {
187180
args.addAll(Arrays.asList("-Werror", "-Xlint:unchecked", "-Xlint:deprecation", "-Xlint:rawtypes",
188181
"-Xlint:varargs"));
189182
}
190183
});
191184
}
192185

193-
private void withOptionalBuildJavaHome(Project project, Consumer<String> consumer) {
194-
String buildJavaHome = (String) project.findProperty("buildJavaHome");
195-
if (buildJavaHome != null && !buildJavaHome.isEmpty()) {
196-
consumer.accept(buildJavaHome);
197-
}
198-
}
199-
200186
private void configureSpringJavaFormat(Project project) {
201187
project.getPlugins().apply(SpringJavaFormatPlugin.class);
202188
project.getTasks().withType(FormatTask.class, (formatTask) -> formatTask.setEncoding("UTF-8"));
@@ -228,4 +214,8 @@ private void configureDependencyManagement(Project project) {
228214
.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME).extendsFrom(dependencyManagement));
229215
}
230216

217+
private void configureToolchain(Project project) {
218+
project.getPlugins().apply(ToolchainPlugin.class);
219+
}
220+
231221
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.toolchain;
18+
19+
import java.util.Optional;
20+
21+
import org.gradle.api.Project;
22+
import org.gradle.jvm.toolchain.JavaLanguageVersion;
23+
24+
/**
25+
* DSL extension for {@link ToolchainPlugin}.
26+
*
27+
* @author Christoph Dreis
28+
*/
29+
public class ToolchainExtension {
30+
31+
private final Project project;
32+
33+
private int maximumCompatibleJavaVersion;
34+
35+
public ToolchainExtension(Project project) {
36+
this.project = project;
37+
}
38+
39+
public void setMaximumCompatibleJavaVersion(int maximumVersion) {
40+
this.maximumCompatibleJavaVersion = maximumVersion;
41+
}
42+
43+
public Optional<JavaLanguageVersion> getToolchainVersion() {
44+
String toolchainVersion = (String) this.project.findProperty("toolchainVersion");
45+
if (toolchainVersion == null) {
46+
return Optional.empty();
47+
}
48+
int version = Integer.parseInt(toolchainVersion);
49+
return getJavaLanguageVersion(version);
50+
}
51+
52+
public boolean isJavaVersionSupported() {
53+
Optional<JavaLanguageVersion> maximumVersion = getJavaLanguageVersion(this.maximumCompatibleJavaVersion);
54+
if (!maximumVersion.isPresent()) {
55+
return true;
56+
}
57+
Optional<JavaLanguageVersion> toolchainVersion = getToolchainVersion();
58+
return toolchainVersion.isPresent() && maximumVersion.get().canCompileOrRun(toolchainVersion.get());
59+
}
60+
61+
private Optional<JavaLanguageVersion> getJavaLanguageVersion(int version) {
62+
if (version >= 8) {
63+
return Optional.of(JavaLanguageVersion.of(version));
64+
}
65+
return Optional.empty();
66+
}
67+
68+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.build.toolchain;
18+
19+
import java.util.Arrays;
20+
import java.util.List;
21+
import java.util.Optional;
22+
23+
import org.gradle.api.Action;
24+
import org.gradle.api.Plugin;
25+
import org.gradle.api.Project;
26+
import org.gradle.api.tasks.compile.JavaCompile;
27+
import org.gradle.api.tasks.javadoc.Javadoc;
28+
import org.gradle.api.tasks.testing.Test;
29+
import org.gradle.jvm.toolchain.JavaLanguageVersion;
30+
import org.gradle.jvm.toolchain.JavaToolchainService;
31+
import org.gradle.jvm.toolchain.JavaToolchainSpec;
32+
33+
/**
34+
* {@link Plugin} for customizing Gradle's toolchain support.
35+
*
36+
* @author Christoph Dreis
37+
*/
38+
public class ToolchainPlugin implements Plugin<Project> {
39+
40+
@Override
41+
public void apply(Project project) {
42+
configureToolchain(project);
43+
}
44+
45+
private void configureToolchain(Project project) {
46+
ToolchainExtension toolchain = project.getExtensions().create("toolchain", ToolchainExtension.class, project);
47+
project.afterEvaluate((evaluated) -> {
48+
Optional<JavaLanguageVersion> toolchainVersion = toolchain.getToolchainVersion();
49+
if (toolchainVersion.isPresent()) {
50+
if (!toolchain.isJavaVersionSupported()) {
51+
disableToolchainTasks(project);
52+
}
53+
else {
54+
configureJavaCompileToolchain(project, toolchain);
55+
configureJavadocToolchain(project, toolchain);
56+
configureTestToolchain(project, toolchain);
57+
}
58+
}
59+
});
60+
}
61+
62+
private void disableToolchainTasks(Project project) {
63+
project.getTasks().withType(JavaCompile.class, (task) -> task.setEnabled(false));
64+
project.getTasks().withType(Javadoc.class, (task) -> task.setEnabled(false));
65+
project.getTasks().withType(Test.class, (task) -> task.setEnabled(false));
66+
}
67+
68+
private void configureJavaCompileToolchain(Project project, ToolchainExtension toolchain) {
69+
project.getTasks().withType(JavaCompile.class, (compile) -> {
70+
withOptionalJavaToolchain(toolchain).ifPresent((action) -> {
71+
JavaToolchainService service = getJavaToolchainService(project);
72+
compile.getJavaCompiler().set(service.compilerFor(action));
73+
compile.getOptions().setFork(true);
74+
// See https://github.com/gradle/gradle/issues/15538
75+
List<String> forkArgs = Arrays.asList("--add-opens",
76+
"jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED");
77+
compile.getOptions().getForkOptions().getJvmArgs().addAll(forkArgs);
78+
});
79+
});
80+
}
81+
82+
private void configureJavadocToolchain(Project project, ToolchainExtension toolchain) {
83+
project.getTasks().withType(Javadoc.class, (javadoc) -> {
84+
withOptionalJavaToolchain(toolchain).ifPresent((action) -> {
85+
JavaToolchainService service = getJavaToolchainService(project);
86+
javadoc.getJavadocTool().set(service.javadocToolFor(action));
87+
});
88+
});
89+
}
90+
91+
private void configureTestToolchain(Project project, ToolchainExtension toolchain) {
92+
project.getTasks().withType(Test.class, (test) -> {
93+
withOptionalJavaToolchain(toolchain).ifPresent((action) -> {
94+
JavaToolchainService service = getJavaToolchainService(project);
95+
test.getJavaLauncher().set(service.launcherFor(action));
96+
// See https://github.com/spring-projects/spring-ldap/issues/570
97+
List<String> arguments = Arrays.asList("--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED",
98+
"--illegal-access=warn");
99+
test.jvmArgs(arguments);
100+
});
101+
});
102+
}
103+
104+
private JavaToolchainService getJavaToolchainService(Project project) {
105+
return project.getExtensions().getByType(JavaToolchainService.class);
106+
}
107+
108+
private Optional<Action<JavaToolchainSpec>> withOptionalJavaToolchain(ToolchainExtension toolchain) {
109+
return toolchain.getToolchainVersion().map((toolchainVersion) -> {
110+
Action<JavaToolchainSpec> action = (javaToolchainSpec) -> javaToolchainSpec.getLanguageVersion()
111+
.convention(toolchainVersion);
112+
return Optional.of(action);
113+
}).orElse(Optional.empty());
114+
}
115+
116+
}

settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ rootProject.name="spring-boot-build"
3131
settings.gradle.projectsLoaded {
3232
gradleEnterprise {
3333
buildScan {
34-
if (settings.gradle.rootProject.hasProperty('buildJavaHome')) {
35-
value('Build Java home', settings.gradle.rootProject.getProperty('buildJavaHome'))
34+
if (settings.gradle.rootProject.hasProperty('toolchainVersion')) {
35+
value('Toolchain Version', settings.gradle.rootProject.getProperty('toolchainVersion'))
3636
}
3737

3838
settings.gradle.rootProject.getBuildDir().mkdirs()

spring-boot-project/spring-boot-cli/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ plugins {
77

88
description = "Spring Boot CLI"
99

10+
toolchain {
11+
maximumCompatibleJavaVersion = 15
12+
}
13+
1014
configurations {
1115
dependenciesBom
1216
loader

spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/json/JsonbTesterTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ plugins {
1010

1111
description = "Spring Boot Gradle Plugin"
1212

13+
toolchain {
14+
maximumCompatibleJavaVersion = 15
15+
}
16+
1317
configurations {
1418
asciidoctorExtensions {
1519
extendsFrom dependencyManagement

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ processResources {
6969
}
7070

7171
compileJava {
72-
if ((!project.hasProperty("buildJavaHome")) && JavaVersion.current() == JavaVersion.VERSION_1_8) {
72+
if ((!project.hasProperty("toolchainVersion")) && JavaVersion.current() == JavaVersion.VERSION_1_8) {
7373
options.compilerArgs += ['-Xlint:-sunapi', '-XDenableSunApiLintControl']
7474
}
7575
}

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.util.zip.ZipEntry;
3131

3232
import org.junit.jupiter.api.TestTemplate;
33+
import org.junit.jupiter.api.condition.DisabledForJreRange;
34+
import org.junit.jupiter.api.condition.JRE;
3335
import org.junit.jupiter.api.extension.ExtendWith;
3436

3537
import org.springframework.boot.loader.tools.FileUtils;
@@ -247,6 +249,7 @@ void whenADependencyHasTestScopeItIsNotIncludedInTheRepackagedJar(MavenBuild mav
247249
});
248250
}
249251

252+
@DisabledForJreRange(min = JRE.JAVA_16) // Remove this once Kotlin supports Java 16
250253
@TestTemplate
251254
void whenAProjectUsesKotlinItsModuleMetadataIsRepackagedIntoBootInfClasses(MavenBuild mavenBuild) {
252255
mavenBuild.project("jar-with-kotlin-module").execute((project) -> {

0 commit comments

Comments
 (0)