24
24
import java .util .Arrays ;
25
25
import java .util .Collections ;
26
26
import java .util .List ;
27
+ import java .util .function .Consumer ;
27
28
28
- import org .springframework .aot .generator .DefaultGeneratedTypeContext ;
29
- import org .springframework .aot .generator .GeneratedType ;
30
- import org .springframework .aot .generator .GeneratedTypeReference ;
29
+ import org .springframework .aot .generate .DefaultGenerationContext ;
30
+ import org .springframework .aot .generate .FileSystemGeneratedFiles ;
31
+ import org .springframework .aot .generate .GeneratedFiles .Kind ;
32
+ import org .springframework .aot .hint .ExecutableHint ;
31
33
import org .springframework .aot .hint .ExecutableMode ;
32
34
import org .springframework .aot .hint .RuntimeHints ;
33
35
import org .springframework .aot .hint .TypeReference ;
34
36
import org .springframework .aot .nativex .FileNativeConfigurationWriter ;
35
- import org .springframework .context .generator .ApplicationContextAotGenerator ;
37
+ import org .springframework .context .aot .ApplicationContextAotGenerator ;
36
38
import org .springframework .context .support .GenericApplicationContext ;
37
39
import org .springframework .javapoet .ClassName ;
38
- import org .springframework .javapoet .JavaFile ;
39
40
import org .springframework .util .Assert ;
40
41
41
42
/**
45
46
*
46
47
* @author Stephane Nicoll
47
48
* @author Andy Wilkinson
49
+ * @author Phillip Webb
48
50
* @since 3.0
49
51
*/
50
52
public class AotProcessor {
51
53
54
+ private static final Consumer <ExecutableHint .Builder > INVOKE_CONSTRUCTOR_HINT = (hint ) -> hint
55
+ .setModes (ExecutableMode .INVOKE );
56
+
52
57
private final Class <?> application ;
53
58
54
59
private final String [] applicationArgs ;
@@ -57,6 +62,8 @@ public class AotProcessor {
57
62
58
63
private final Path resourceOutput ;
59
64
65
+ private final Path classOutput ;
66
+
60
67
private final String groupId ;
61
68
62
69
private final String artifactId ;
@@ -67,17 +74,19 @@ public class AotProcessor {
67
74
* @param applicationArgs the arguments to provide to the main method
68
75
* @param sourceOutput the location of generated sources
69
76
* @param resourceOutput the location of generated resources
77
+ * @param classOutput the location of generated classes
70
78
* @param groupId the group ID of the application, used to locate
71
79
* native-image.properties
72
80
* @param artifactId the artifact ID of the application, used to locate
73
81
* native-image.properties
74
82
*/
75
83
public AotProcessor (Class <?> application , String [] applicationArgs , Path sourceOutput , Path resourceOutput ,
76
- String groupId , String artifactId ) {
84
+ Path classOutput , String groupId , String artifactId ) {
77
85
this .application = application ;
78
86
this .applicationArgs = applicationArgs ;
79
87
this .sourceOutput = sourceOutput ;
80
88
this .resourceOutput = resourceOutput ;
89
+ this .classOutput = classOutput ;
81
90
this .groupId = groupId ;
82
91
this .artifactId = artifactId ;
83
92
}
@@ -104,36 +113,39 @@ private void callApplicationMainMethod() {
104
113
}
105
114
106
115
private void performAotProcessing (GenericApplicationContext applicationContext ) {
107
- DefaultGeneratedTypeContext generationContext = new DefaultGeneratedTypeContext (
108
- this .application .getPackageName (), (packageName ) -> GeneratedType .of (ClassName .get (packageName ,
109
- this .application .getSimpleName () + "__ApplicationContextInitializer" )));
116
+ FileSystemGeneratedFiles generatedFiles = new FileSystemGeneratedFiles (this ::getRoot );
117
+ DefaultGenerationContext generationContext = new DefaultGenerationContext (generatedFiles );
110
118
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator ();
111
- generator .generateApplicationContext (applicationContext , generationContext );
112
-
113
- // Register reflection hint for entry point as we access it via reflection
114
- generationContext .runtimeHints ().reflection ()
115
- .registerType (GeneratedTypeReference .of (generationContext .getMainGeneratedType ().getClassName ()),
116
- (hint ) -> hint .onReachableType (TypeReference .of (this .application )).withConstructor (
117
- Collections .emptyList (),
118
- (constructorHint ) -> constructorHint .setModes (ExecutableMode .INVOKE )));
119
-
120
- writeGeneratedSources (generationContext .toJavaFiles ());
121
- writeGeneratedResources (generationContext .runtimeHints ());
119
+ ClassName generatedInitializerClassName = generationContext .getClassNameGenerator ()
120
+ .generateClassName (this .application , "ApplicationContextInitializer" );
121
+ generator .generateApplicationContext (applicationContext , generationContext , generatedInitializerClassName );
122
+ registerEntryPointHint (generationContext , generatedInitializerClassName );
123
+ generationContext .writeGeneratedContent ();
124
+ writeHints (generationContext .getRuntimeHints ());
122
125
writeNativeImageProperties ();
123
126
}
124
127
125
- private void writeGeneratedSources (List <JavaFile > sources ) {
126
- for (JavaFile source : sources ) {
127
- try {
128
- source .writeTo (this .sourceOutput );
129
- }
130
- catch (IOException ex ) {
131
- throw new IllegalStateException ("Failed to write " + source .typeSpec .name , ex );
132
- }
128
+ private void registerEntryPointHint (DefaultGenerationContext generationContext ,
129
+ ClassName generatedInitializerClassName ) {
130
+ TypeReference generatedType = TypeReference .of (generatedInitializerClassName .canonicalName ());
131
+ TypeReference applicationType = TypeReference .of (this .application );
132
+ generationContext .getRuntimeHints ().reflection ().registerType (generatedType , (hint ) -> hint
133
+ .onReachableType (applicationType ).withConstructor (Collections .emptyList (), INVOKE_CONSTRUCTOR_HINT ));
134
+ }
135
+
136
+ private Path getRoot (Kind kind ) {
137
+ switch (kind ) {
138
+ case SOURCE :
139
+ return this .sourceOutput ;
140
+ case RESOURCE :
141
+ return this .resourceOutput ;
142
+ case CLASS :
143
+ return this .classOutput ;
133
144
}
145
+ throw new IllegalStateException ("Unsupported kind " + kind );
134
146
}
135
147
136
- private void writeGeneratedResources (RuntimeHints hints ) {
148
+ private void writeHints (RuntimeHints hints ) {
137
149
FileNativeConfigurationWriter writer = new FileNativeConfigurationWriter (this .resourceOutput , this .groupId ,
138
150
this .artifactId );
139
151
writer .write (hints );
@@ -164,21 +176,22 @@ private void writeNativeImageProperties() {
164
176
}
165
177
166
178
public static void main (String [] args ) throws Exception {
167
- int requiredArgs = 5 ;
179
+ int requiredArgs = 6 ;
168
180
if (args .length < requiredArgs ) {
169
181
throw new IllegalArgumentException ("Usage: " + AotProcessor .class .getName ()
170
- + " <applicationName> <sourceOutput> <resourceOutput> <groupId> <artifactId> <originalArgs...>" );
182
+ + " <applicationName> <sourceOutput> <resourceOutput> <classOutput> < groupId> <artifactId> <originalArgs...>" );
171
183
}
172
184
String applicationName = args [0 ];
173
185
Path sourceOutput = Paths .get (args [1 ]);
174
186
Path resourceOutput = Paths .get (args [2 ]);
175
- String groupId = args [3 ];
176
- String artifactId = args [4 ];
187
+ Path classOutput = Paths .get (args [3 ]);
188
+ String groupId = args [4 ];
189
+ String artifactId = args [5 ];
177
190
String [] applicationArgs = (args .length > requiredArgs ) ? Arrays .copyOfRange (args , requiredArgs , args .length )
178
191
: new String [0 ];
179
192
Class <?> application = Class .forName (applicationName );
180
- AotProcessor aotProcess = new AotProcessor (application , applicationArgs , sourceOutput , resourceOutput , groupId ,
181
- artifactId );
193
+ AotProcessor aotProcess = new AotProcessor (application , applicationArgs , sourceOutput , resourceOutput ,
194
+ classOutput , groupId , artifactId );
182
195
aotProcess .process ();
183
196
}
184
197
0 commit comments