|
2 | 2 |
|
3 | 3 | import static java.util.List.of;
|
4 | 4 | import static java.util.Map.entry;
|
5 |
| -import static java.util.stream.Collectors.joining; |
6 | 5 | import static java.util.stream.Collectors.toList;
|
7 | 6 |
|
8 | 7 | import java.io.FileWriter;
|
@@ -113,8 +112,7 @@ static void registerModuleProvidedTypes(Set<String> providedTypes) {
|
113 | 112 | static void registerPluginProvidedTypes(ScopeInfo defaultScope) {
|
114 | 113 | if (!INJECT_AVAILABLE) {
|
115 | 114 | if (!pluginExists("avaje-module-dependencies.csv")) {
|
116 |
| - APContext.logNote( |
117 |
| - "Unable to detect Avaje Inject Maven/Gradle plugin, use the Avaje Inject Maven/Gradle plugin for auto detecting External Inject Plugins/Modules from dependencies"); |
| 115 | + APContext.logNote("Unable to detect Avaje Inject Maven/Gradle plugin, use the Avaje Inject Maven/Gradle plugin for auto detecting External Inject Plugins/Modules from dependencies"); |
118 | 116 | }
|
119 | 117 | return;
|
120 | 118 | }
|
@@ -165,162 +163,155 @@ static void readMetaDataProvides(Collection<String> providedTypes) {
|
165 | 163 | }
|
166 | 164 |
|
167 | 165 | static void scanAllInjectPlugins(ScopeInfo defaultScope) {
|
168 |
| - final var noPlugins = !defaultScope.pluginProvided().isEmpty(); |
169 |
| - |
170 |
| - avajePlugins.forEach( |
171 |
| - (k, v) -> { |
172 |
| - if (APContext.typeElement(k) != null) { |
173 |
| - APContext.logNote("Loaded Plugin: %s", k); |
174 |
| - v.forEach(defaultScope::pluginProvided); |
175 |
| - } |
176 |
| - }); |
| 166 | + final var hasPlugins = !defaultScope.pluginProvided().isEmpty(); |
| 167 | + avajePlugins.forEach((k, v) -> { |
| 168 | + if (APContext.typeElement(k) != null) { |
| 169 | + APContext.logNote("Loaded Plugin: %s", k); |
| 170 | + v.forEach(defaultScope::pluginProvided); |
| 171 | + } |
| 172 | + }); |
177 | 173 | defaultScope.pluginProvided("io.avaje.inject.event.ObserverManager");
|
178 |
| - |
179 |
| - if (noPlugins) { |
| 174 | + if (hasPlugins) { |
180 | 175 | return;
|
181 | 176 | }
|
182 | 177 |
|
183 |
| - var stream = getInjectExtensions(); |
184 |
| - stream |
185 |
| - .filter(PluginProvidesPrism::isPresent) |
186 |
| - .distinct() |
187 |
| - .forEach( |
188 |
| - t -> { |
189 |
| - final var name = t.getQualifiedName().toString(); |
190 |
| - if (avajePlugins.containsKey(name)) { |
191 |
| - return; |
192 |
| - } |
193 |
| - |
194 |
| - var prism = PluginProvidesPrism.getInstanceOn(t); |
195 |
| - |
196 |
| - for (final var provide : prism.provides()) { |
197 |
| - defaultScope.pluginProvided(provide.toString()); |
198 |
| - } |
199 |
| - for (final var provide : prism.providesStrings()) { |
200 |
| - defaultScope.pluginProvided(provide); |
201 |
| - } |
202 |
| - for (final var provide : prism.providesAspects()) { |
203 |
| - defaultScope.pluginProvided(Util.wrapAspect(provide.toString())); |
204 |
| - } |
205 |
| - |
206 |
| - APContext.logNote("Loaded Plugin: %s", name); |
207 |
| - }); |
| 178 | + injectExtensions() |
| 179 | + .filter(PluginProvidesPrism::isPresent) |
| 180 | + .distinct() |
| 181 | + .forEach(pluginType -> addPluginToScope(defaultScope, pluginType)); |
| 182 | + |
208 | 183 | if (defaultScope.pluginProvided().isEmpty()) {
|
209 | 184 | APContext.logNote("No external plugins detected");
|
210 | 185 | }
|
| 186 | + writePluginProvides(defaultScope); |
| 187 | + } |
211 | 188 |
|
| 189 | + private static void writePluginProvides(ScopeInfo defaultScope) { |
212 | 190 | // write detected plugins to a text file for test compilation
|
213 |
| - try (var pluginWriter = |
214 |
| - new FileWriter(APContext.getBuildResource("avaje-plugin-provides.txt").toFile())) { |
215 |
| - |
| 191 | + try (final var pluginWriter = new FileWriter(APContext.getBuildResource("avaje-plugin-provides.txt").toFile())) { |
216 | 192 | for (var providedType : defaultScope.pluginProvided()) {
|
217 |
| - |
218 | 193 | pluginWriter.write(providedType);
|
219 | 194 | pluginWriter.write("\n");
|
220 | 195 | }
|
221 |
| - |
222 | 196 | } catch (IOException e) {
|
223 |
| - e.printStackTrace(); |
| 197 | + APContext.logWarn("Failed to write avaje-plugin-provides.txt due to %s", e.getMessage()); |
224 | 198 | }
|
225 | 199 | }
|
226 | 200 |
|
| 201 | + private static void addPluginToScope(ScopeInfo defaultScope, TypeElement pluginType) { |
| 202 | + final var name = pluginType.getQualifiedName().toString(); |
| 203 | + if (avajePlugins.containsKey(name)) { |
| 204 | + return; |
| 205 | + } |
| 206 | + var prism = PluginProvidesPrism.getInstanceOn(pluginType); |
| 207 | + for (final var provide : prism.provides()) { |
| 208 | + defaultScope.pluginProvided(provide.toString()); |
| 209 | + } |
| 210 | + for (final var provide : prism.providesStrings()) { |
| 211 | + defaultScope.pluginProvided(provide); |
| 212 | + } |
| 213 | + for (final var provide : prism.providesAspects()) { |
| 214 | + defaultScope.pluginProvided(Util.wrapAspect(provide.toString())); |
| 215 | + } |
| 216 | + APContext.logNote("Loaded Plugin: %s", name); |
| 217 | + } |
| 218 | + |
227 | 219 | static void scanAllAvajeModules(Collection<String> providedTypes) {
|
228 | 220 | if (!externalMeta.isEmpty()) {
|
229 | 221 | return;
|
230 | 222 | }
|
231 |
| - var stream = getInjectExtensions(); |
232 |
| - |
233 |
| - var types = APContext.types(); |
234 |
| - var spi = APContext.typeElement("io.avaje.inject.spi.AvajeModule").asType(); |
235 |
| - stream |
236 |
| - .filter(t -> t.getInterfaces().stream().anyMatch(i -> types.isAssignable(i, spi))) |
237 |
| - .distinct() |
238 |
| - .forEach( |
239 |
| - t -> { |
240 |
| - final var provides = new HashSet<String>(); |
241 |
| - final var requires = new HashSet<String>(); |
242 |
| - |
243 |
| - ElementFilter.methodsIn(t.getEnclosedElements()).stream() |
244 |
| - .map(DependencyMetaPrism::getInstanceOn) |
245 |
| - .filter(Objects::nonNull) |
246 |
| - .map(MetaData::new) |
247 |
| - .forEach( |
248 |
| - m -> { |
249 |
| - externalMeta.add(m); |
250 |
| - provides.addAll(m.autoProvides()); |
251 |
| - provides.addAll(m.provides()); |
252 |
| - m.dependsOn().stream() |
253 |
| - .filter(d -> !d.isSoftDependency()) |
254 |
| - .map(Dependency::name) |
255 |
| - .forEach(requires::add); |
256 |
| - |
257 |
| - providedTypes.add(m.key()); |
258 |
| - providedTypes.add(m.type()); |
259 |
| - providedTypes.addAll(Util.addQualifierSuffix(m.provides(), m.name())); |
260 |
| - providedTypes.addAll(Util.addQualifierSuffix(m.autoProvides(), m.name())); |
261 |
| - }); |
262 |
| - |
263 |
| - final var name = t.getQualifiedName().toString(); |
264 |
| - APContext.logNote("Detected Module: %s", name); |
265 |
| - ProcessingContext.addModule( |
266 |
| - new ModuleData(name, List.copyOf(provides), List.copyOf(requires))); |
267 |
| - }); |
| 223 | + final var types = APContext.types(); |
| 224 | + final var avajeModuleType = APContext.typeElement("io.avaje.inject.spi.AvajeModule").asType(); |
| 225 | + injectExtensions() |
| 226 | + .filter(t -> t.getInterfaces().stream().anyMatch(i -> types.isAssignable(i, avajeModuleType))) |
| 227 | + .distinct() |
| 228 | + .forEach(otherModule -> addOtherModuleProvides(providedTypes, otherModule)); |
| 229 | + |
268 | 230 | if (externalMeta.isEmpty()) {
|
269 | 231 | APContext.logNote("No external modules detected");
|
270 | 232 | }
|
| 233 | + writeModuleDependencies(); |
| 234 | + } |
271 | 235 |
|
| 236 | + private static void writeModuleDependencies() { |
272 | 237 | // write detected modules to a csv for test compilation
|
273 |
| - try (var moduleWriter = |
274 |
| - new FileWriter(APContext.getBuildResource("avaje-module-dependencies.csv").toFile())) { |
275 |
| - |
| 238 | + try (final var moduleWriter = new FileWriter(APContext.getBuildResource("avaje-module-dependencies.csv").toFile())) { |
276 | 239 | moduleWriter.write("External Module Type|Provides|Requires");
|
277 | 240 | for (ModuleData avajeModule : ProcessingContext.modules()) {
|
278 | 241 | moduleWriter.write("\n");
|
279 | 242 | moduleWriter.write(avajeModule.name());
|
280 | 243 | moduleWriter.write("|");
|
281 |
| - var provides = avajeModule.provides().stream().collect(joining(",")); |
| 244 | + var provides = String.join(",", avajeModule.provides()); |
282 | 245 | moduleWriter.write(provides.isEmpty() ? " " : provides);
|
283 | 246 | moduleWriter.write("|");
|
284 |
| - var requires = avajeModule.requires().stream().collect(joining(",")); |
| 247 | + var requires = String.join(",", avajeModule.requires()); |
285 | 248 | moduleWriter.write(requires.isEmpty() ? " " : requires);
|
286 | 249 | }
|
287 | 250 |
|
288 | 251 | } catch (IOException e) {
|
289 |
| - e.printStackTrace(); |
| 252 | + APContext.logWarn("Failed to write avaje-module-dependencies.csv due to %s", e.getMessage()); |
290 | 253 | }
|
291 | 254 | }
|
292 | 255 |
|
293 |
| - private static Stream<TypeElement> getInjectExtensions() { |
294 |
| - var allModules = |
295 |
| - APContext.elements().getAllModuleElements().stream() |
296 |
| - .filter(m -> !m.getQualifiedName().toString().startsWith("java")) |
297 |
| - .filter(m -> !m.getQualifiedName().toString().startsWith("jdk")) |
298 |
| - // for whatever reason, compilation breaks if we don't filter out the current module |
299 |
| - .filter(m -> !m.equals(APContext.getProjectModuleElement())) |
300 |
| - .collect(toList()); |
| 256 | + private static void addOtherModuleProvides(Collection<String> providedTypes, TypeElement otherModule) { |
| 257 | + final var provides = new HashSet<String>(); |
| 258 | + final var requires = new HashSet<String>(); |
| 259 | + |
| 260 | + ElementFilter.methodsIn(otherModule.getEnclosedElements()).stream() |
| 261 | + .map(DependencyMetaPrism::getInstanceOn) |
| 262 | + .filter(Objects::nonNull) |
| 263 | + .map(MetaData::new) |
| 264 | + .forEach(m -> { |
| 265 | + externalMeta.add(m); |
| 266 | + provides.addAll(m.autoProvides()); |
| 267 | + provides.addAll(m.provides()); |
| 268 | + m.dependsOn().stream() |
| 269 | + .filter(d -> !d.isSoftDependency()) |
| 270 | + .map(Dependency::name) |
| 271 | + .forEach(requires::add); |
| 272 | + |
| 273 | + providedTypes.add(m.key()); |
| 274 | + providedTypes.add(m.type()); |
| 275 | + providedTypes.addAll(Util.addQualifierSuffix(m.provides(), m.name())); |
| 276 | + providedTypes.addAll(Util.addQualifierSuffix(m.autoProvides(), m.name())); |
| 277 | + }); |
| 278 | + |
| 279 | + final var name = otherModule.getQualifiedName().toString(); |
| 280 | + APContext.logNote("Detected Module: %s", name); |
| 281 | + ProcessingContext.addModule(new ModuleData(name, List.copyOf(provides), List.copyOf(requires))); |
| 282 | + } |
| 283 | + |
| 284 | + private static Stream<TypeElement> injectExtensions() { |
| 285 | + final var allModules = |
| 286 | + APContext.elements().getAllModuleElements().stream() |
| 287 | + .filter(m -> !m.getQualifiedName().toString().startsWith("java")) |
| 288 | + .filter(m -> !m.getQualifiedName().toString().startsWith("jdk")) |
| 289 | + // for whatever reason, compilation breaks if we don't filter out the current module |
| 290 | + .filter(m -> !m.equals(APContext.getProjectModuleElement())) |
| 291 | + .collect(toList()); |
301 | 292 |
|
302 |
| - var types = APContext.types(); |
303 |
| - var spi = APContext.typeElement("io.avaje.inject.spi.InjectExtension").asType(); |
| 293 | + final var types = APContext.types(); |
| 294 | + final var extensionType = APContext.typeElement("io.avaje.inject.spi.InjectExtension").asType(); |
304 | 295 |
|
305 | 296 | final var checkEnclosing =
|
306 |
| - allModules.stream() |
307 |
| - .flatMap(m -> m.getEnclosedElements().stream()) |
308 |
| - .flatMap(p -> p.getEnclosedElements().stream()) |
309 |
| - .map(TypeElement.class::cast) |
310 |
| - .filter(t -> t.getKind() == ElementKind.CLASS) |
311 |
| - .filter(t -> t.getModifiers().contains(Modifier.PUBLIC)) |
312 |
| - .filter(t -> types.isAssignable(t.asType(), spi)); |
| 297 | + allModules.stream() |
| 298 | + .flatMap(m -> m.getEnclosedElements().stream()) |
| 299 | + .flatMap(p -> p.getEnclosedElements().stream()) |
| 300 | + .map(TypeElement.class::cast) |
| 301 | + .filter(t -> t.getKind() == ElementKind.CLASS) |
| 302 | + .filter(t -> t.getModifiers().contains(Modifier.PUBLIC)) |
| 303 | + .filter(t -> types.isAssignable(t.asType(), extensionType)); |
313 | 304 |
|
314 | 305 | final var checkDirectives =
|
315 |
| - allModules.stream() |
316 |
| - .flatMap(m -> ElementFilter.providesIn(m.getDirectives()).stream()) |
317 |
| - .filter(ExternalProvider::isInjectExtension) |
318 |
| - .flatMap(p -> p.getImplementations().stream()); |
| 306 | + allModules.stream() |
| 307 | + .flatMap(m -> ElementFilter.providesIn(m.getDirectives()).stream()) |
| 308 | + .filter(ExternalProvider::isInjectExtension) |
| 309 | + .flatMap(p -> p.getImplementations().stream()); |
| 310 | + |
319 | 311 | return Stream.concat(checkEnclosing, checkDirectives);
|
320 | 312 | }
|
321 | 313 |
|
322 | 314 | private static boolean isInjectExtension(ModuleElement.ProvidesDirective p) {
|
323 |
| - return "io.avaje.inject.spi.InjectExtension" |
324 |
| - .equals(p.getService().getQualifiedName().toString()); |
| 315 | + return "io.avaje.inject.spi.InjectExtension".equals(p.getService().getQualifiedName().toString()); |
325 | 316 | }
|
326 | 317 | }
|
0 commit comments