Skip to content

Commit eadb003

Browse files
committed
Introduce builder API for AOT processor Settings
Closes gh-29341
1 parent cb44e09 commit eadb003

File tree

4 files changed

+254
-75
lines changed

4 files changed

+254
-75
lines changed

Diff for: spring-context/src/main/java/org/springframework/context/aot/AbstractAotProcessor.java

+114-63
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.aot.hint.RuntimeHints;
2525
import org.springframework.aot.nativex.FileNativeConfigurationWriter;
2626
import org.springframework.lang.Nullable;
27+
import org.springframework.util.Assert;
2728
import org.springframework.util.FileSystemUtils;
2829

2930
/**
@@ -49,6 +50,7 @@ public abstract class AbstractAotProcessor {
4950

5051
/**
5152
* Create a new processor instance with the supplied {@linkplain Settings settings}.
53+
* @see Settings#builder()
5254
*/
5355
protected AbstractAotProcessor(Settings settings) {
5456
this.settings = settings;
@@ -102,114 +104,163 @@ protected void writeHints(RuntimeHints hints) {
102104
/**
103105
* Common settings for AOT processors.
104106
*/
105-
public static class Settings {
107+
public static final class Settings {
106108

107-
@Nullable
108-
private Path sourceOutput;
109+
private final Path sourceOutput;
109110

110-
@Nullable
111-
private Path resourceOutput;
111+
private final Path resourceOutput;
112112

113-
@Nullable
114-
private Path classOutput;
113+
private final Path classOutput;
115114

116-
@Nullable
117-
private String groupId;
115+
private final String groupId;
118116

119-
@Nullable
120-
private String artifactId;
117+
private final String artifactId;
121118

122119

123-
/**
124-
* Set the output directory for generated sources.
125-
* @param sourceOutput the location of generated sources
126-
* @return this settings object for method chaining
127-
*/
128-
public Settings setSourceOutput(Path sourceOutput) {
120+
private Settings(Path sourceOutput, Path resourceOutput, Path classOutput, String groupId, String artifactId) {
129121
this.sourceOutput = sourceOutput;
130-
return this;
122+
this.resourceOutput = resourceOutput;
123+
this.classOutput = classOutput;
124+
this.groupId = groupId;
125+
this.artifactId = artifactId;
131126
}
132127

128+
133129
/**
134-
* Get the output directory for generated sources.
130+
* Create a new {@link Builder} for {@link Settings}.
135131
*/
136-
@Nullable
137-
public Path getSourceOutput() {
138-
return this.sourceOutput;
132+
public static Builder builder() {
133+
return new Builder();
139134
}
140135

136+
141137
/**
142-
* Set the output directory for generated resources.
143-
* @param resourceOutput the location of generated resources
144-
* @return this settings object for method chaining
138+
* Get the output directory for generated sources.
145139
*/
146-
public Settings setResourceOutput(Path resourceOutput) {
147-
this.resourceOutput = resourceOutput;
148-
return this;
140+
public Path getSourceOutput() {
141+
return this.sourceOutput;
149142
}
150143

151144
/**
152145
* Get the output directory for generated resources.
153146
*/
154-
@Nullable
155147
public Path getResourceOutput() {
156148
return this.resourceOutput;
157149
}
158150

159-
/**
160-
* Set the output directory for generated classes.
161-
* @param classOutput the location of generated classes
162-
* @return this settings object for method chaining
163-
*/
164-
public Settings setClassOutput(Path classOutput) {
165-
this.classOutput = classOutput;
166-
return this;
167-
}
168-
169151
/**
170152
* Get the output directory for generated classes.
171153
*/
172-
@Nullable
173154
public Path getClassOutput() {
174155
return this.classOutput;
175156
}
176157

177-
/**
178-
* Set the group ID of the application.
179-
* @param groupId the group ID of the application, used to locate
180-
* {@code native-image.properties}
181-
* @return this settings object for method chaining
182-
*/
183-
public Settings setGroupId(String groupId) {
184-
this.groupId = groupId;
185-
return this;
186-
}
187-
188158
/**
189159
* Get the group ID of the application.
190160
*/
191-
@Nullable
192161
public String getGroupId() {
193162
return this.groupId;
194163
}
195164

196165
/**
197-
* Set the artifact ID of the application.
198-
* @param artifactId the artifact ID of the application, used to locate
199-
* {@code native-image.properties}
200-
* @return this settings object for method chaining
166+
* Get the artifact ID of the application.
201167
*/
202-
public Settings setArtifactId(String artifactId) {
203-
this.artifactId = artifactId;
204-
return this;
168+
public String getArtifactId() {
169+
return this.artifactId;
205170
}
206171

172+
207173
/**
208-
* Get the artifact ID of the application.
174+
* Fluent builder API for {@link Settings}.
209175
*/
210-
@Nullable
211-
public String getArtifactId() {
212-
return this.artifactId;
176+
public static final class Builder {
177+
178+
@Nullable
179+
private Path sourceOutput;
180+
181+
@Nullable
182+
private Path resourceOutput;
183+
184+
@Nullable
185+
private Path classOutput;
186+
187+
@Nullable
188+
private String groupId;
189+
190+
@Nullable
191+
private String artifactId;
192+
193+
194+
private Builder() {
195+
// internal constructor
196+
}
197+
198+
199+
/**
200+
* Set the output directory for generated sources.
201+
* @param sourceOutput the location of generated sources
202+
* @return this builder for method chaining
203+
*/
204+
public Builder sourceOutput(Path sourceOutput) {
205+
this.sourceOutput = sourceOutput;
206+
return this;
207+
}
208+
209+
/**
210+
* Set the output directory for generated resources.
211+
* @param resourceOutput the location of generated resources
212+
* @return this builder for method chaining
213+
*/
214+
public Builder resourceOutput(Path resourceOutput) {
215+
this.resourceOutput = resourceOutput;
216+
return this;
217+
}
218+
219+
/**
220+
* Set the output directory for generated classes.
221+
* @param classOutput the location of generated classes
222+
* @return this builder for method chaining
223+
*/
224+
public Builder classOutput(Path classOutput) {
225+
this.classOutput = classOutput;
226+
return this;
227+
}
228+
229+
/**
230+
* Set the group ID of the application.
231+
* @param groupId the group ID of the application, used to locate
232+
* {@code native-image.properties}
233+
* @return this builder for method chaining
234+
*/
235+
public Builder groupId(String groupId) {
236+
this.groupId = groupId;
237+
return this;
238+
}
239+
240+
/**
241+
* Set the artifact ID of the application.
242+
* @param artifactId the artifact ID of the application, used to locate
243+
* {@code native-image.properties}
244+
* @return this builder for method chaining
245+
*/
246+
public Builder artifactId(String artifactId) {
247+
this.artifactId = artifactId;
248+
return this;
249+
}
250+
251+
/**
252+
* Build the {@link Settings} configured in this {@code Builder}.
253+
*/
254+
public Settings build() {
255+
Assert.notNull(this.sourceOutput, "'sourceOutput' must not be null");
256+
Assert.notNull(this.resourceOutput, "'resourceOutput' must not be null");
257+
Assert.notNull(this.classOutput, "'classOutput' must not be null");
258+
Assert.hasText(this.groupId, "'groupId' must not be null or empty");
259+
Assert.hasText(this.artifactId, "'artifactId' must not be null or empty");
260+
return new Settings(this.sourceOutput, this.resourceOutput, this.classOutput,
261+
this.groupId, this.artifactId);
262+
}
263+
213264
}
214265

215266
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2002-2022 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.context.aot;
18+
19+
import java.nio.file.Path;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.io.TempDir;
23+
24+
import org.springframework.context.aot.AbstractAotProcessor.Settings;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
28+
29+
/**
30+
* Tests for {@link AbstractAotProcessor}, settings, and builder.
31+
*
32+
* @author Sam Brannen
33+
* @since 6.0
34+
*/
35+
class AotProcessorTests {
36+
37+
@Test
38+
void builderRejectsMissingSourceOutput() {
39+
assertThatIllegalArgumentException()
40+
.isThrownBy(() -> Settings.builder().build())
41+
.withMessageContaining("'sourceOutput'");
42+
}
43+
44+
@Test
45+
void builderRejectsMissingResourceOutput(@TempDir Path tempDir) {
46+
assertThatIllegalArgumentException()
47+
.isThrownBy(() -> Settings.builder().sourceOutput(tempDir).build())
48+
.withMessageContaining("'resourceOutput'");
49+
}
50+
51+
@Test
52+
void builderRejectsMissingClassOutput(@TempDir Path tempDir) {
53+
assertThatIllegalArgumentException()
54+
.isThrownBy(() -> Settings.builder()
55+
.sourceOutput(tempDir)
56+
.resourceOutput(tempDir)
57+
.build())
58+
.withMessageContaining("'classOutput'");
59+
}
60+
61+
@Test
62+
void builderRejectsMissingGroupdId(@TempDir Path tempDir) {
63+
assertThatIllegalArgumentException()
64+
.isThrownBy(() -> Settings.builder()
65+
.sourceOutput(tempDir)
66+
.resourceOutput(tempDir)
67+
.classOutput(tempDir)
68+
.build())
69+
.withMessageContaining("'groupId'");
70+
}
71+
72+
@Test
73+
void builderRejectsEmptyGroupdId(@TempDir Path tempDir) {
74+
assertThatIllegalArgumentException()
75+
.isThrownBy(() -> Settings.builder()
76+
.sourceOutput(tempDir)
77+
.resourceOutput(tempDir)
78+
.classOutput(tempDir)
79+
.groupId(" ")
80+
.build())
81+
.withMessageContaining("'groupId'");
82+
}
83+
84+
@Test
85+
void builderRejectsMissingArtifactId(@TempDir Path tempDir) {
86+
assertThatIllegalArgumentException()
87+
.isThrownBy(() -> Settings.builder()
88+
.sourceOutput(tempDir)
89+
.resourceOutput(tempDir)
90+
.classOutput(tempDir)
91+
.groupId("my-group")
92+
.build())
93+
.withMessageContaining("'artifactId'");
94+
}
95+
96+
@Test
97+
void builderRejectsEmptyArtifactId(@TempDir Path tempDir) {
98+
assertThatIllegalArgumentException()
99+
.isThrownBy(() -> Settings.builder()
100+
.sourceOutput(tempDir)
101+
.resourceOutput(tempDir)
102+
.classOutput(tempDir)
103+
.groupId("my-group")
104+
.artifactId(" ")
105+
.build())
106+
.withMessageContaining("'artifactId'");
107+
}
108+
109+
@Test
110+
void builderAcceptsRequiredSettings(@TempDir Path tempDir) {
111+
Settings settings = Settings.builder()
112+
.sourceOutput(tempDir)
113+
.resourceOutput(tempDir)
114+
.classOutput(tempDir)
115+
.groupId("my-group")
116+
.artifactId("my-artifact")
117+
.build();
118+
assertThat(settings).isNotNull();
119+
assertThat(settings.getSourceOutput()).isEqualTo(tempDir);
120+
assertThat(settings.getResourceOutput()).isEqualTo(tempDir);
121+
assertThat(settings.getClassOutput()).isEqualTo(tempDir);
122+
assertThat(settings.getGroupId()).isEqualTo("my-group");
123+
assertThat(settings.getArtifactId()).isEqualTo("my-artifact");
124+
}
125+
126+
}

Diff for: spring-context/src/test/java/org/springframework/context/aot/ContextAotProcessorTests.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,13 @@ private static class DemoContextAotProcessor extends ContextAotProcessor {
128128

129129
private static Settings createSettings(Path sourceOutput, Path resourceOutput,
130130
Path classOutput, String groupId, String artifactId) {
131-
return new Settings()
132-
.setSourceOutput(sourceOutput)
133-
.setResourceOutput(resourceOutput)
134-
.setClassOutput(classOutput)
135-
.setArtifactId(artifactId)
136-
.setGroupId(groupId);
131+
return Settings.builder()
132+
.sourceOutput(sourceOutput)
133+
.resourceOutput(resourceOutput)
134+
.classOutput(classOutput)
135+
.artifactId(artifactId)
136+
.groupId(groupId)
137+
.build();
137138
}
138139

139140
@Override

0 commit comments

Comments
 (0)