Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 55e0540

Browse files
bclozelsnicoll
authored andcommitted
Support AOT options in build plugins
Prior to this commit, the `BootstrapCodeGeneratorRunner` was implemented as a simple class with a `main` method that is passed arguments as positional parameters only. This would miss most AotOptions supported so far and could be quite difficult to maintain. This commit renames the runner to `GenerateBootstrap` and turns it into a picocli CLI command with bound options and parameters. This now supports all `remove*Support` options and some more. The Maven and Gradle build plugins have been updated accordingly to call the command with the expected arguments. This commit also removes the need to push the classpath as a command parameter and automatically extracts it using the `"java.class.path"` system property. Fixes gh-989
1 parent c95ba4a commit 55e0540

File tree

7 files changed

+181
-115
lines changed

7 files changed

+181
-115
lines changed

pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
<artifactId>android-json</artifactId>
109109
<version>0.0.20131108.vaadin1</version>
110110
</dependency>
111+
<dependency>
112+
<groupId>info.picocli</groupId>
113+
<artifactId>picocli</artifactId>
114+
<version>4.6.1</version>
115+
</dependency>
111116
<dependency>
112117
<groupId>com.wavefront</groupId>
113118
<artifactId>wavefront-spring-boot</artifactId>

spring-aot-gradle-plugin/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ plugins {
33
}
44

55
java {
6-
sourceCompatibility = JavaVersion.VERSION_1_8
7-
targetCompatibility = JavaVersion.VERSION_1_8
6+
sourceCompatibility = JavaVersion.VERSION_11
7+
targetCompatibility = JavaVersion.VERSION_11
88
}
99

1010
dependencies {

spring-aot-gradle-plugin/src/main/java/org/springframework/aot/gradle/tasks/GenerateAotSources.java

+32-19
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@
3434
import org.gradle.api.tasks.Nested;
3535
import org.gradle.api.tasks.OutputDirectory;
3636
import org.gradle.process.CommandLineArgumentProvider;
37-
import org.slf4j.LoggerFactory;
3837

3938
import org.springframework.aot.BootstrapCodeGenerator;
40-
import org.springframework.aot.context.bootstrap.BootstrapCodeGeneratorRunner;
39+
import org.springframework.aot.context.bootstrap.GenerateBootstrap;
4140
import org.springframework.aot.gradle.dsl.SpringAotExtension;
41+
import org.springframework.nativex.AotOptions;
4242
import org.springframework.util.StringUtils;
4343

4444
/**
@@ -64,7 +64,7 @@ public GenerateAotSources() {
6464
this.sourcesOutputDirectory = getProject().getObjects().directoryProperty();
6565
this.resourcesOutputDirectory = getProject().getObjects().directoryProperty();
6666
this.aotOptions = new GenerateAotOptions(getProject().getExtensions().findByType(SpringAotExtension.class));
67-
setMain(BootstrapCodeGeneratorRunner.class.getCanonicalName());
67+
setMain(GenerateBootstrap.class.getCanonicalName());
6868
getArgumentProviders().add(new BootstrapGeneratorArgumentProvider());
6969
}
7070

@@ -102,19 +102,29 @@ private class BootstrapGeneratorArgumentProvider implements CommandLineArgumentP
102102
@Override
103103
public Iterable<String> asArguments() {
104104
List<String> arguments = new ArrayList<>();
105-
// path to generated sources
106-
arguments.add(GenerateAotSources.this.sourcesOutputDirectory.get().getAsFile().toPath().toString());
107-
// path to generated resources
108-
arguments.add(GenerateAotSources.this.resourcesOutputDirectory.get().getAsFile().toPath().toString());
109-
// application resources locations
110-
arguments.add(toPathArgument(GenerateAotSources.this.resourceDirectories.getSrcDirs()));
111-
// application classes locations
112-
arguments.add(GenerateAotSources.this.mainSourceSetOutputDirectory.get().getAsFile().toPath().toString());
113-
// application classpath
114-
arguments.add(toPathArgument(getClasspath().getFiles()));
115-
// log level
116-
arguments.add(getLogLevel());
117-
105+
AotOptions aotOptions = getAotOptions().toAotOptions();
106+
arguments.add("--sources-out=" + GenerateAotSources.this.sourcesOutputDirectory.get().getAsFile().toPath());
107+
arguments.add("--resources-out=" + GenerateAotSources.this.resourcesOutputDirectory.get().getAsFile().toPath());
108+
arguments.add("--resources=" + toPathArgument(GenerateAotSources.this.resourceDirectories.getSrcDirs()));
109+
arguments.add("--classes=" + GenerateAotSources.this.mainSourceSetOutputDirectory.get().getAsFile().toPath());
110+
if (aotOptions.isRemoveXmlSupport()) {
111+
arguments.add("--remove-xml");
112+
}
113+
if (aotOptions.isRemoveJmxSupport()) {
114+
arguments.add("--remove-jmx");
115+
}
116+
if (aotOptions.isRemoveSpelSupport()) {
117+
arguments.add("--remove-spel");
118+
}
119+
if (aotOptions.isRemoveYamlSupport()) {
120+
arguments.add("--remove-yaml");
121+
}
122+
if (aotOptions.isBuildTimePropertyChecking()) {
123+
arguments.add("--props=" + StringUtils.arrayToCommaDelimitedString(aotOptions.getBuildTimePropertiesChecks()));
124+
}
125+
if (getLogLevel().equals("DEBUG")) {
126+
arguments.add("--debug");
127+
}
118128
// main application class
119129
if (GenerateAotSources.this.aotOptions.getMainClass().isPresent()) {
120130
arguments.add(GenerateAotSources.this.aotOptions.getMainClass().get());
@@ -126,11 +136,14 @@ private String getLogLevel() {
126136
Logger rootLogger = Logging.getLogger(Logger.ROOT_LOGGER_NAME);
127137
if (rootLogger.isDebugEnabled()) {
128138
return "DEBUG";
129-
} else if (rootLogger.isInfoEnabled()) {
139+
}
140+
else if (rootLogger.isInfoEnabled()) {
130141
return "INFO";
131-
} else if (rootLogger.isWarnEnabled()) {
142+
}
143+
else if (rootLogger.isWarnEnabled()) {
132144
return "WARN";
133-
} else {
145+
}
146+
else {
134147
return "ERROR";
135148
}
136149
}

spring-aot-maven-plugin/src/main/java/org/springframework/aot/maven/GenerateMojo.java

+35-21
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636
import org.codehaus.plexus.util.xml.Xpp3Dom;
3737
import org.twdata.maven.mojoexecutor.MojoExecutor;
3838

39-
import org.springframework.aot.context.bootstrap.BootstrapCodeGeneratorRunner;
39+
import org.springframework.aot.context.bootstrap.GenerateBootstrap;
4040
import org.springframework.boot.loader.tools.RunProcess;
41+
import org.springframework.nativex.AotOptions;
4142
import org.springframework.nativex.support.Mode;
4243
import org.springframework.util.StringUtils;
4344

@@ -87,10 +88,13 @@ public void execute() throws MojoExecutionException, MojoFailureException {
8788
.ifPresent(artifact -> runtimeClasspathElements.add(1, artifact.getFile().getAbsolutePath()));
8889
findJarFile(this.pluginArtifacts, "com.squareup", "javapoet")
8990
.ifPresent(artifact -> runtimeClasspathElements.add(1, artifact.getFile().getAbsolutePath()));
91+
findJarFile(this.pluginArtifacts, "info.picocli", "picocli")
92+
.ifPresent(artifact -> runtimeClasspathElements.add(1, artifact.getFile().getAbsolutePath()));
9093
findJarFile(this.pluginArtifacts, "net.bytebuddy", "byte-buddy")
9194
.ifPresent(artifact -> runtimeClasspathElements.add(1, artifact.getFile().getAbsolutePath()));
9295

93-
if (getAotOptions().toMode().equals(Mode.NATIVE)) {
96+
AotOptions aotOptions = getAotOptions();
97+
if (aotOptions.toMode().equals(Mode.NATIVE)) {
9498
RunProcess runProcess = new RunProcess(Paths.get(this.project.getBuild().getDirectory()).toFile(), getJavaExecutable());
9599
Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess)));
96100

@@ -100,24 +104,31 @@ public void execute() throws MojoExecutionException, MojoFailureException {
100104
args.add("-Xdebug");
101105
args.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + this.codeGenDebugPort);
102106
}
103-
// plugin classpath
104107
args.add("-cp");
105108
args.add(asClasspathArgument(runtimeClasspathElements));
106-
// main class
107-
args.add(BootstrapCodeGeneratorRunner.class.getCanonicalName());
108-
// [0] sourcesPath
109-
args.add(sourcesPath.toAbsolutePath().toString());
110-
// [1] resourcesPath
111-
args.add(resourcesPath.toAbsolutePath().toString());
112-
// [2] resourcesFolders
113-
args.add(StringUtils.collectionToDelimitedString(resourceFolders, File.pathSeparator));
114-
// [3] classesFolder
115-
args.add(project.getBuild().getOutputDirectory());
116-
// [4] classPathElements
117-
args.add(StringUtils.collectionToDelimitedString(runtimeClasspathElements, File.pathSeparator));
118-
// [5] log level
119-
args.add(getLogLevel());
120-
// [6] Application main class
109+
args.add(GenerateBootstrap.class.getCanonicalName());
110+
args.add("--sources-out=" + sourcesPath.toAbsolutePath());
111+
args.add("--resources-out=" + resourcesPath.toAbsolutePath());
112+
args.add("--resources=" + StringUtils.collectionToDelimitedString(resourceFolders, File.pathSeparator));
113+
args.add("--classes=" + project.getBuild().getOutputDirectory());
114+
if (aotOptions.isRemoveXmlSupport()) {
115+
args.add("--remove-xml");
116+
}
117+
if (aotOptions.isRemoveJmxSupport()) {
118+
args.add("--remove-jmx");
119+
}
120+
if (aotOptions.isRemoveSpelSupport()) {
121+
args.add("--remove-spel");
122+
}
123+
if (aotOptions.isRemoveYamlSupport()) {
124+
args.add("--remove-yaml");
125+
}
126+
if (aotOptions.isBuildTimePropertyChecking()) {
127+
args.add("--props=" + StringUtils.arrayToCommaDelimitedString(aotOptions.getBuildTimePropertiesChecks()));
128+
}
129+
if (getLogLevel().equals("DEBUG")) {
130+
args.add("--debug");
131+
}
121132
if (this.mainClass != null) {
122133
args.add(this.mainClass);
123134
}
@@ -144,11 +155,14 @@ public void execute() throws MojoExecutionException, MojoFailureException {
144155
private String getLogLevel() {
145156
if (getLog().isDebugEnabled()) {
146157
return "DEBUG";
147-
} else if (getLog().isInfoEnabled()) {
158+
}
159+
else if (getLog().isInfoEnabled()) {
148160
return "INFO";
149-
} else if (getLog().isWarnEnabled()) {
161+
}
162+
else if (getLog().isWarnEnabled()) {
150163
return "WARN";
151-
} else {
164+
}
165+
else {
152166
return "ERROR";
153167
}
154168
}

spring-aot/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
<groupId>net.bytebuddy</groupId>
3434
<artifactId>byte-buddy</artifactId>
3535
</dependency>
36+
<dependency>
37+
<groupId>info.picocli</groupId>
38+
<artifactId>picocli</artifactId>
39+
</dependency>
3640

3741
<dependency>
3842
<groupId>org.springframework</groupId>

spring-aot/src/main/java/org/springframework/aot/context/bootstrap/BootstrapCodeGeneratorRunner.java

-73
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2002-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.aot.context.bootstrap;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.nio.file.Path;
22+
import java.util.Arrays;
23+
import java.util.Collections;
24+
import java.util.List;
25+
import java.util.Set;
26+
import java.util.concurrent.Callable;
27+
28+
import picocli.CommandLine;
29+
import picocli.CommandLine.Command;
30+
import picocli.CommandLine.Option;
31+
import picocli.CommandLine.Parameters;
32+
33+
import org.springframework.aot.ApplicationStructure;
34+
import org.springframework.aot.BootstrapCodeGenerator;
35+
import org.springframework.boot.logging.LoggingSystem;
36+
import org.springframework.nativex.AotOptions;
37+
import org.springframework.util.StringUtils;
38+
39+
@Command(mixinStandardHelpOptions = true,
40+
description = "Generate the Java source for the Spring Bootstrap class.")
41+
public class GenerateBootstrap implements Callable<Integer> {
42+
43+
@Parameters(index = "0", arity = "0..1", description = "The main application class, auto-detected if not provided.")
44+
private String mainClass;
45+
46+
@Option(names = {"--sources-out"}, required = true, description = "Output path for the generated sources.")
47+
private Path sourceOutputPath;
48+
49+
@Option(names = {"--resources-out"}, required = true, description = "Output path for the generated resources.")
50+
private Path resourcesOutputPath;
51+
52+
@Option(names = {"--classes"}, required = true, split = "${sys:path.separator}", description = "Paths to the application compiled classes.")
53+
private List<Path> classesPaths;
54+
55+
@Option(names = {"--resources"}, required = true, split = "${sys:path.separator}", description = "Paths to the application compiled resources.")
56+
private Set<Path> resourcesPaths;
57+
58+
@Option(names = {"--debug"}, description = "Enable debug logging.")
59+
private boolean isDebug;
60+
61+
@Option(names = {"--remove-yaml"}, description = "Remove Yaml support.")
62+
private boolean removeYaml;
63+
64+
@Option(names = {"--remove-jmx"}, description = "Remove JMX support.")
65+
private boolean removeJmx;
66+
67+
@Option(names = {"--remove-xml"}, description = "Remove XML support.")
68+
private boolean removeXml;
69+
70+
@Option(names = {"--remove-spel"}, description = "Remove SpEL support.")
71+
private boolean removeSpel;
72+
73+
@Option(names = {"--props"}, split = ",", description = "Build time properties checks.")
74+
private List<String> propertiesCheck = Collections.emptyList();
75+
76+
@Override
77+
public Integer call() throws Exception {
78+
AotOptions aotOptions = new AotOptions();
79+
aotOptions.setDebugVerify(this.isDebug);
80+
aotOptions.setRemoveYamlSupport(this.removeYaml);
81+
aotOptions.setRemoveJmxSupport(this.removeJmx);
82+
aotOptions.setRemoveXmlSupport(this.removeXml);
83+
aotOptions.setRemoveSpelSupport(this.removeSpel);
84+
aotOptions.setBuildTimePropertiesChecks(propertiesCheck.toArray(new String[0]));
85+
86+
String[] classPath = StringUtils.tokenizeToStringArray(System.getProperty("java.class.path"), File.pathSeparator);
87+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
88+
if (!this.isDebug) {
89+
LoggingSystem loggingSystem = LoggingSystem.get(classLoader);
90+
loggingSystem.beforeInitialize();
91+
}
92+
BootstrapCodeGenerator generator = new BootstrapCodeGenerator(aotOptions);
93+
ApplicationStructure applicationStructure = new ApplicationStructure(this.sourceOutputPath, this.resourcesOutputPath, this.resourcesPaths,
94+
this.classesPaths.get(0), this.mainClass, Arrays.asList(classPath), classLoader);
95+
generator.generate(applicationStructure);
96+
return 0;
97+
}
98+
99+
public static void main(String[] args) throws IOException {
100+
int exitCode = new CommandLine(new GenerateBootstrap()).execute(args);
101+
System.exit(exitCode);
102+
}
103+
}

0 commit comments

Comments
 (0)