From 5edc776b0b4fb738d72fede63134c3528b19f612 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:14:38 -0400 Subject: [PATCH 1/9] use strings for provides/requires this prevents issues where auto provided/required types not available during compilation or plugin activation fail builds --- .../inject/generator/ExternalProvider.java | 34 +++--- .../io/avaje/inject/generator/ScopeInfo.java | 26 ++--- .../inject/generator/SimpleModuleWriter.java | 16 ++- .../avaje/inject/mojo/AutoProvidesMojo.java | 49 +++++---- .../io/avaje/inject/DBeanScopeBuilder.java | 46 ++++---- .../java/io/avaje/inject/spi/AvajeModule.java | 101 +++++++++++++++--- .../io/avaje/inject/spi/InjectPlugin.java | 34 +++--- 7 files changed, 194 insertions(+), 112 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java index cca10b4c9..f159717a3 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java @@ -6,10 +6,10 @@ import java.io.FileWriter; import java.io.IOException; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -84,24 +84,22 @@ static void registerModuleProvidedTypes(Set providedTypes) { for (final var module : modules) { final var name = module.getClass().getTypeName(); final var provides = new TreeSet(); - for (final var provide : module.provides()) { - provides.add(provide.getTypeName()); - } - for (final var provide : module.autoProvides()) { - provides.add(provide.getTypeName()); - } - for (final var provide : module.autoProvidesAspects()) { - final var aspectType = Util.wrapAspect(provide.getTypeName()); + Collections.addAll(provides, module.providesBeans()); + Collections.addAll(provides, module.autoProvidesBeans()); + for (final var provide : module.autoProvidesAspectBeans()) { + final var aspectType = Util.wrapAspect(provide); provides.add(aspectType); } registerExternalMetaData(name); readMetaDataProvides(provides); providedTypes.addAll(provides); - final var requires = Arrays.stream(module.requires()).map(Type::getTypeName).collect(toList()); - - Arrays.stream(module.autoRequires()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.requiresPackages()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.autoRequiresAspects()).map(Type::getTypeName).map(Util::wrapAspect).forEach(requires::add); + final List requires = new ArrayList<>(); + Collections.addAll(requires, module.requiresBeans()); + Collections.addAll(requires, module.autoRequiresBeans()); + Collections.addAll(requires, module.requiresPackagesFromType()); + Arrays.stream(module.autoRequiresAspectBeans()) + .map(Util::wrapAspect) + .forEach(requires::add); ProcessingContext.addModule(new ModuleData(name, List.copyOf(provides), requires)); } @@ -127,11 +125,11 @@ static void registerPluginProvidedTypes(ScopeInfo defaultScope) { continue; } APContext.logNote("Loaded Plugin: %s", plugin.getClass().getTypeName()); - for (final var provide : plugin.provides()) { - defaultScope.pluginProvided(provide.getTypeName()); + for (final var provide : plugin.providesBeans()) { + defaultScope.pluginProvided(provide); } - for (final var provide : plugin.providesAspects()) { - defaultScope.pluginProvided(Util.wrapAspect(provide.getTypeName())); + for (final var provide : plugin.providesAspectBeans()) { + defaultScope.pluginProvided(Util.wrapAspect(provide)); } } } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java index 9596791d7..fd0722038 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java @@ -429,32 +429,26 @@ private void attributeClasses(boolean leadingComma, Append writer, String prefix void buildProvides(Append writer) { if (!provides.isEmpty()) { - buildProvidesMethod(writer, "provides", provides); + buildProvidesMethod(writer, "providesBeans", provides); } if (!requires.isEmpty()) { - buildProvidesMethod(writer, "requires", requires); + buildProvidesMethod(writer, "requiresBeans", requires); } if (!requiresPackages.isEmpty()) { - buildProvidesMethod(writer, "requiresPackages", requiresPackages); + buildProvidesMethod(writer, "requiresPackagesFromType", requiresPackages); } } private void buildProvidesMethod(Append writer, String fieldName, Set types) { writer.append(" @Override").eol(); - final var arrayType = fieldName.contains("Aspects") ? "Class" : "Type"; - writer.append(" public %s[] %s() {", arrayType, fieldName).eol(); - writer.append(" return new %s[] {", arrayType).eol(); + writer.append(" public String[] %s() {", fieldName).eol(); + writer.append(" return new String[] {").eol(); for (final String rawType : types) { if (rawType.contains(":")) { continue; } - - if (rawType.contains("<")) { - writer.append(" new GenericType<%s>(){},", rawType).eol(); - } else { - writer.append(" %s.class,", rawType).eol(); - } + writer.append(" \"%s\",", rawType).eol(); } writer.append(" };").eol(); writer.append(" }").eol().eol(); @@ -463,28 +457,28 @@ private void buildProvidesMethod(Append writer, String fieldName, Set ty void buildAutoProvides(Append writer, Set autoProvides) { autoProvides.removeAll(provides); if (!autoProvides.isEmpty()) { - buildProvidesMethod(writer, "autoProvides", autoProvides); + buildProvidesMethod(writer, "autoProvidesBeans", autoProvides); } } void buildAutoProvidesAspects(Append writer, Set autoProvidesAspects) { autoProvidesAspects.removeAll(provides); if (!autoProvidesAspects.isEmpty()) { - buildProvidesMethod(writer, "autoProvidesAspects", autoProvidesAspects); + buildProvidesMethod(writer, "autoProvidesAspectBeans", autoProvidesAspects); } } void buildAutoRequires(Append writer, Set autoRequires) { autoRequires.removeAll(requires); if (!autoRequires.isEmpty()) { - buildProvidesMethod(writer, "autoRequires", autoRequires); + buildProvidesMethod(writer, "autoRequiresBeans", autoRequires); } } void buildAutoRequiresAspects(Append writer, Set autoRequires) { autoRequires.removeAll(requires); if (!autoRequires.isEmpty()) { - buildProvidesMethod(writer, "autoRequiresAspects", autoRequires); + buildProvidesMethod(writer, "autoRequiresAspectBeans", autoRequires); } } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java index 2fe9f5b78..13b1dbf94 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java @@ -1,13 +1,23 @@ package io.avaje.inject.generator; -import static io.avaje.inject.generator.APContext.*; -import static io.avaje.inject.generator.ProcessingContext.*; +import static io.avaje.inject.generator.APContext.logError; +import static io.avaje.inject.generator.APContext.typeElement; +import static io.avaje.inject.generator.ProcessingContext.allScopes; +import static io.avaje.inject.generator.ProcessingContext.createMetaInfWriterFor; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import java.io.IOException; import java.io.Writer; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Predicate; import java.util.stream.Stream; diff --git a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java index 2f15349e0..678bcbbd5 100644 --- a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java +++ b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java @@ -5,12 +5,12 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -85,14 +85,16 @@ private List compileDependencies() throws MojoExecutionException { } private URLClassLoader createClassLoader(List listUrl) { - return new URLClassLoader(listUrl.toArray(new URL[listUrl.size()]), Thread.currentThread().getContextClassLoader()); + return new URLClassLoader( + listUrl.toArray(new URL[listUrl.size()]), Thread.currentThread().getContextClassLoader()); } private FileWriter createFileWriter(String string) throws IOException { return new FileWriter(new File(project.getBuild().getDirectory(), string)); } - private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter pluginWriter) throws IOException { + private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter pluginWriter) + throws IOException { final Log log = getLog(); final List plugins = new ArrayList<>(); @@ -105,15 +107,13 @@ private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter plug final Map> pluginEntries = new HashMap<>(); for (final var plugin : plugins) { final List provides = new ArrayList<>(); - final var typeName = plugin.getClass().getTypeName(); + final var typeName = plugin.getClass(); log.info("Loaded Plugin: " + typeName); - for (final var provide : plugin.provides()) { - provides.add(provide.getTypeName()); - } + Collections.addAll(provides,plugin.providesBeans()); for (final var provide : plugin.providesAspects()) { provides.add(wrapAspect(provide.getCanonicalName())); } - pluginEntries.put(typeName, provides); + pluginEntries.put(typeName.getTypeName(), provides); } pluginWriter.write("External Plugin Type|Provides"); @@ -126,7 +126,8 @@ private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter plug } } - private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) throws IOException { + private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) + throws IOException { final Log log = getLog(); final List avajeModules = new ArrayList<>(); ServiceLoader.load(InjectExtension.class, newClassLoader).stream() @@ -137,35 +138,33 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) List modules = new ArrayList<>(); for (final var module : avajeModules) { - final var name = module.getClass().getTypeName(); + final var name = module.getClass(); log.info("Detected External Module: " + name); final var provides = new ArrayList(); - for (final var provide : module.provides()) { - var type = provide.getTypeName(); + for (final var provide : module.providesBeans()) { + var type = provide; provides.add(type); } - for (final var provide : module.autoProvides()) { - var type = provide.getTypeName(); + for (final var provide : module.autoProvidesBeans()) { + var type = provide; provides.add(type); } - for (final var provide : module.autoProvidesAspects()) { - var type = wrapAspect(provide.getTypeName()); + for (final var provide : module.autoProvidesAspectBeans()) { + var type = wrapAspect(provide); provides.add(type); } - final var requires = - Arrays.stream(module.requires()).map(Type::getTypeName).collect(toList()); + final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); - Arrays.stream(module.autoRequires()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.requiresPackages()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.autoRequiresAspects()) - .map(Type::getTypeName) - .map(AutoProvidesMojo::wrapAspect) - .forEach(requires::add); - modules.add(new ModuleData(name, provides, requires)); + Arrays.stream(module.autoRequiresBeans()).forEach(requires::add); + Arrays.stream(module.requiresPackagesFromType()).forEach(requires::add); + Arrays.stream(module.autoRequiresAspectBeans()) + .map(AutoProvidesMojo::wrapAspect) + .forEach(requires::add); + modules.add(new ModuleData(name.getTypeName(), provides, requires)); } moduleWriter.write("External Module Type|Provides|Requires"); diff --git a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java index 813ac0b94..a8261d449 100644 --- a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java +++ b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java @@ -326,9 +326,9 @@ public void add(AvajeModule module) { .computeIfAbsent(module.getClass().getTypeName(), s -> new FactoryList()) .add(factoryState); - addFactoryProvides(factoryState, module.provides()); - addFactoryProvides(factoryState, module.autoProvides()); - addFactoryProvides(factoryState, module.autoProvidesAspects()); + addFactoryProvides(factoryState, module.providesBeans()); + addFactoryProvides(factoryState, module.autoProvidesBeans()); + addFactoryProvides(factoryState, module.autoProvidesAspectBeans()); if (factoryState.isRequiresEmpty()) { if (factoryState.explicitlyProvides()) { @@ -344,9 +344,9 @@ public void add(AvajeModule module) { } } - private void addFactoryProvides(FactoryState factoryState, Type[] provides) { + private void addFactoryProvides(FactoryState factoryState, String[] provides) { for (final var feature : provides) { - providesMap.computeIfAbsent(feature.getTypeName(), s -> new FactoryList()).add(factoryState); + providesMap.computeIfAbsent(feature, s -> new FactoryList()).add(factoryState); } } @@ -403,10 +403,10 @@ private void processQueue() { } } - private void unsatisfiedRequires(StringBuilder sb, Type[] requiredType, String requires) { + private void unsatisfiedRequires(StringBuilder sb, String[] requiredType, String requires) { for (final var depModuleName : requiredType) { - if (notProvided(depModuleName.getTypeName())) { - sb.append(String.format(" %s [%s]", requires, depModuleName.getTypeName())); + if (notProvided(depModuleName)) { + sb.append(String.format(" %s [%s]", requires, depModuleName)); } } } @@ -447,9 +447,9 @@ && satisfiedDependencies(factory.autoRequiresAspects()) && satisfiedDependencies(factory.autoRequires()); } - private boolean satisfiedDependencies(Type[] requires) { + private boolean satisfiedDependencies(String[] requires) { for (final var dependency : requires) { - if (notProvided(dependency.getTypeName())) { + if (notProvided(dependency)) { return false; } } @@ -485,20 +485,20 @@ AvajeModule factory() { return factory; } - Type[] requires() { - return factory.requires(); + String[] requires() { + return factory.requiresBeans(); } - Type[] requiresPackages() { - return factory.requiresPackages(); + String[] requiresPackages() { + return factory.requiresPackagesFromType(); } - Type[] autoRequires() { - return factory.autoRequires(); + String[] autoRequires() { + return factory.autoRequiresBeans(); } - Type[] autoRequiresAspects() { - return factory.autoRequiresAspects(); + String[] autoRequiresAspects() { + return factory.autoRequiresAspectBeans(); } @Override @@ -507,15 +507,17 @@ public String toString() { } boolean isRequiresEmpty() { - return isEmpty(factory.requires()) && isEmpty(factory.requiresPackages()) - && isEmpty(factory.autoRequires()) && isEmpty(factory.autoRequiresAspects()); + return isEmpty(factory.requiresBeans()) + && isEmpty(factory.requiresPackagesFromType()) + && isEmpty(factory.autoRequiresBeans()) + && isEmpty(factory.autoRequiresAspectBeans()); } boolean explicitlyProvides() { - return !isEmpty(factory.provides()); + return !isEmpty(factory.providesBeans()); } - private boolean isEmpty(@Nullable Type[] values) { + private boolean isEmpty(@Nullable String[] values) { return values == null || values.length == 0; } } diff --git a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java index 1cfb33e72..daab44d99 100644 --- a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java +++ b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java @@ -1,58 +1,114 @@ package io.avaje.inject.spi; import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Objects; -/** - * A Module containing dependencies that will be included in BeanScope. - */ +/** A Module containing dependencies that will be included in BeanScope. */ public interface AvajeModule extends InjectExtension { - /** - * Empty array of classes. - */ + /** Empty array of classes. */ + @Deprecated(forRemoval = true) Class[] EMPTY_CLASSES = {}; + /** Empty array of strings. */ + String[] EMPTY_STRINGS = {}; + /** * Return the set of types this module explicitly provides to other modules. + * + * @deprecated use {@link #providesBeans()} */ + @Deprecated(forRemoval = true) default Type[] provides() { return EMPTY_CLASSES; } + /** Return the type names of types this module explicitly provides to other modules. */ + default String[] providesBeans() { + return Arrays.stream(Objects.requireNonNullElse(provides(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * Return the types this module needs to be provided externally or via other modules. + * + * @deprecated use {@link #requiresBeans()} */ + @Deprecated(forRemoval = true) default Type[] requires() { return EMPTY_CLASSES; } + /** + * Return the type names of types this module needs to be provided externally or via other + * modules. + */ + default String[] requiresBeans() { + return Arrays.stream(Objects.requireNonNullElse(requires(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * Return the packages this module needs to be provided via other modules. + * + * @deprecated use {@link #requiresPackagesFromType()} */ + @Deprecated(forRemoval = true) default Type[] requiresPackages() { return EMPTY_CLASSES; } + /** Return the type names of packages this module needs to be provided via other modules. */ + default String[] requiresPackagesFromType() { + return Arrays.stream(Objects.requireNonNullElse(requiresPackages(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * Return the classes that this module provides that we allow other modules to auto depend on. * *

This is a convenience when using multiple modules that is otherwise controlled manually by * explicitly using {@link AvajeModule#provides()}. + * + * @deprecated use {@link #autoProvidesBeans()} */ + @Deprecated(forRemoval = true) default Type[] autoProvides() { return EMPTY_CLASSES; } + /** + * Return the type names of classes that this module provides that we allow other modules to auto + * depend on. + */ + default String[] autoProvidesBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoProvides(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * Return the aspects that this module provides. * *

This is a convenience when using multiple modules that we otherwise manually specify via * {@link AvajeModule#provides()}. */ + @Deprecated(forRemoval = true) default Class[] autoProvidesAspects() { return EMPTY_CLASSES; } + /** Return the type names of aspects that this module provides. */ + default String[] autoProvidesAspectBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoProvidesAspects(), EMPTY_CLASSES)) + .map(Class::getTypeName) + .toArray(String[]::new); + } + /** * These are the classes that this module requires for wiring that are provided by other external * modules (that are in the classpath at compile time). @@ -60,18 +116,40 @@ default Class[] autoProvidesAspects() { *

This is a convenience when using multiple modules that is otherwise controlled manually by * explicitly using {@link AvajeModule#requires()} or {@link AvajeModule#requiresPackages()}. */ + @Deprecated(forRemoval = true) default Type[] autoRequires() { return EMPTY_CLASSES; } + /** + * Return the type names of classes that this module requires for wiring that are provided by + * other external modules. + */ + default String[] autoRequiresBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoRequires(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * These are the aspects that this module requires whose implementations are provided by other * external modules (that are in the classpath at compile time). */ + @Deprecated(forRemoval = true) default Class[] autoRequiresAspects() { return EMPTY_CLASSES; } + /** + * Return the type names of aspects that this module requires whose implementations are provided + * by other external modules. + */ + default String[] autoRequiresAspectBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoRequiresAspects(), EMPTY_CLASSES)) + .map(Class::getTypeName) + .toArray(String[]::new); + } + /** * Return public classes of the beans that would be registered by this module. * @@ -80,14 +158,9 @@ default Class[] autoRequiresAspects() { */ Class[] classes(); - /** - * Build all the beans. - */ + /** Build all the beans. */ void build(Builder builder); - /** - * Marker for custom scoped modules. - */ - interface Custom extends AvajeModule { - } + /** Marker for custom scoped modules. */ + interface Custom extends AvajeModule {} } diff --git a/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java b/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java index 3677b88a7..103ba7412 100644 --- a/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java +++ b/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java @@ -1,8 +1,9 @@ package io.avaje.inject.spi; -import io.avaje.inject.BeanScopeBuilder; - import java.lang.reflect.Type; +import java.util.Arrays; + +import io.avaje.inject.BeanScopeBuilder; /** * A Plugin that can be applied when creating a bean scope. @@ -12,27 +13,32 @@ */ public interface InjectPlugin extends InjectExtension { - /** - * Empty array of classes. - */ + /** Empty array of classes. */ Class[] EMPTY_CLASSES = {}; - /** - * Apply the plugin to the scope builder. - */ + /** Empty array of classes. */ + String[] EMPTY_STRINGS = {}; + + /** Apply the plugin to the scope builder. */ void apply(BeanScopeBuilder builder); - /** - * Return the classes that the plugin provides. - */ + /** Return the classes that the plugin provides. */ default Type[] provides() { return EMPTY_CLASSES; } - /** - * Return the aspect classes that the plugin provides. - */ + /** Return the type names of types this module explicitly provides to other modules. */ + default String[] providesBeans() { + return Arrays.stream(provides()).map(Type::getTypeName).toArray(String[]::new); + } + + /** Return the aspect classes that the plugin provides. */ default Class[] providesAspects() { return EMPTY_CLASSES; } + + /** Return the type names of types this module explicitly provides to other modules. */ + default String[] providesAspectBeans() { + return Arrays.stream(providesAspects()).map(Type::getTypeName).toArray(String[]::new); + } } From e56664ebaf9e37e1c12dbefe0b412831ef2992f4 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:29:47 -0400 Subject: [PATCH 2/9] allow generics in `@InjectModule` --- .../io/avaje/inject/generator/ScopeInfo.java | 22 +++++++++++-- .../generator/models/valid/_Wiring.java | 6 ++-- .../java/io/avaje/inject/InjectModule.java | 32 +++++++++++++------ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java index fd0722038..9bcf9bddf 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java @@ -130,6 +130,8 @@ private void read(Element element) { ignoreSingleton = injectModule.ignoreSingleton(); injectModule.requires().stream().map(Object::toString).forEach(requires::add); injectModule.provides().stream().map(Object::toString).forEach(provides::add); + requires.addAll(injectModule.requiresString()); + provides.addAll(injectModule.providesString()); injectModule.requiresPackages().stream() .map(Object::toString) .forEach( @@ -392,11 +394,11 @@ void buildAtInjectModule(Append writer) { writer.append("@InjectModule("); boolean leadingComma = false; if (!provides.isEmpty()) { - attributeClasses(false, writer, "provides", provides); + attributeString(false, writer, "providesString", provides); leadingComma = true; } if (!requires.isEmpty()) { - attributeClasses(leadingComma, writer, "requires", requires); + attributeString(leadingComma, writer, "requiresString", requires); leadingComma = true; } if (!requiresPackages.isEmpty()) { @@ -412,6 +414,22 @@ void buildAtInjectModule(Append writer) { writer.append(")").eol(); } + private void attributeString( + boolean leadingComma, Append writer, String prefix, Set classNames) { + if (leadingComma) { + writer.append(", "); + } + writer.append("%s = {", prefix); + int c = 0; + for (final String value : classNames) { + if (c++ > 0) { + writer.append(","); + } + writer.append("\"%s\"", value); + } + writer.append("}"); + } + private void attributeClasses(boolean leadingComma, Append writer, String prefix, Set classNames) { if (leadingComma) { writer.append(", "); diff --git a/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/_Wiring.java b/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/_Wiring.java index 9dd537014..973217dbb 100644 --- a/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/_Wiring.java +++ b/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/_Wiring.java @@ -2,7 +2,7 @@ import io.avaje.inject.Factory; import io.avaje.inject.InjectModule; -@InjectModule(strictWiring = true) + +@InjectModule(strictWiring = true, providesString = "java.util.Queue") @Factory -public class _Wiring { -} \ No newline at end of file +public class _Wiring {} diff --git a/inject/src/main/java/io/avaje/inject/InjectModule.java b/inject/src/main/java/io/avaje/inject/InjectModule.java index a1e31af3d..d9265e350 100644 --- a/inject/src/main/java/io/avaje/inject/InjectModule.java +++ b/inject/src/main/java/io/avaje/inject/InjectModule.java @@ -76,24 +76,36 @@ boolean ignoreSingleton() default false; /** - * Explicitly define features that are provided by this module and required by other modules. - *

- * This is used to order wiring across multiple modules. Modules that provide dependencies + * Explicitly define beans that are provided by this module and required by other modules. + * + *

This is used to order wiring across multiple modules. Modules that provide dependencies * should be wired before modules that require dependencies. */ Class[] provides() default {}; /** - * The dependencies that are provided externally or by other modules and that are required - * when wiring this module. - *

- * This effectively tells the annotation processor that these types are expected to be - * provided and to not treat them as missing dependencies. If we don't do this the annotation - * processor thinks the dependency is missing and will error the compilation saying there is - * a missing dependency. + * Required external beans for wiring this module. + * + *

This tells the annotation processor that these types are expected to be provided and to not + * treat them as missing dependencies. If we don't do this the annotation processor thinks the + * dependency is missing and will error the compilation saying there is a missing dependency. */ Class[] requires() default {}; + /** + * Explicitly define beans provided by this module and required by other modules. + * + * @see #provides() + */ + String[] providesString() default {}; + + /** + * Required external beans for wiring this module. + * + * @see #requires() + */ + String[] requiresString() default {}; + /** * Dependencies in these packages are expected to be provided by other modules. *

From b2b2f72e700c8a21492777e8a51326f4d0fda91f Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:53:04 -0400 Subject: [PATCH 3/9] gradle --- .../inject/plugin/AvajeInjectPlugin.java | 27 +++++++++---------- .../avaje/inject/mojo/AutoProvidesMojo.java | 6 ++--- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java index 8fa751ab8..bab001186 100644 --- a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java +++ b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java @@ -74,10 +74,10 @@ private void writeProvidedPlugins(ClassLoader classLoader, FileWriter pluginWrit final List provides = new ArrayList<>(); final var typeName = plugin.getClass().getTypeName(); System.out.println("Loaded Plugin: " + typeName); - for (final var provide : plugin.provides()) { - provides.add(provide.getTypeName()); + for (final var provide : plugin.providesBeans()) { + provides.add(provide); } - for (final var provide : plugin.providesAspects()) { + for (final var provide : plugin.providesAspectBeans()) { provides.add(wrapAspect(provide.getCanonicalName())); } pluginEntries.put(typeName, provides); @@ -129,25 +129,24 @@ private void writeModuleCSV(ClassLoader classLoader, FileWriter moduleWriter) th System.out.println("Detected External Module: " + name); final var provides = new ArrayList(); - for (final var provide : module.provides()) { - var type = provide.getTypeName(); + for (final var provide : module.providesBeans()) { + var type = provide; provides.add(type); } - for (final var provide : module.autoProvides()) { - var type = provide.getTypeName(); + for (final var provide : module.autoProvidesBeans()) { + var type = provide; provides.add(type); } - for (final var provide : module.autoProvidesAspects()) { - var type = wrapAspect(provide.getTypeName()); + for (final var provide : module.autoprovidesAspectBeans()) { + var type = wrapAspect(provide); provides.add(type); } - final var requires = Arrays.stream(module.requires()).map(Type::getTypeName).collect(toList()); + final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); - Arrays.stream(module.autoRequires()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.requiresPackages()).map(Type::getTypeName).forEach(requires::add); - Arrays.stream(module.autoRequiresAspects()) - .map(Type::getTypeName) + Arrays.stream(module.autoRequires()).forEach(requires::add); + Arrays.stream(module.requiresPackages()).forEach(requires::add); + Arrays.stream(module.autoRequiresAspects()) .map(AvajeInjectPlugin::wrapAspect) .forEach(requires::add); modules.add(new ModuleData(name, provides, requires)); diff --git a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java index 678bcbbd5..7a8e3d4de 100644 --- a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java +++ b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java @@ -109,7 +109,7 @@ private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter plug final List provides = new ArrayList<>(); final var typeName = plugin.getClass(); log.info("Loaded Plugin: " + typeName); - Collections.addAll(provides,plugin.providesBeans()); + Collections.addAll(provides, plugin.providesBeans()); for (final var provide : plugin.providesAspects()) { provides.add(wrapAspect(provide.getCanonicalName())); } @@ -159,8 +159,8 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); - Arrays.stream(module.autoRequiresBeans()).forEach(requires::add); - Arrays.stream(module.requiresPackagesFromType()).forEach(requires::add); + Collections.addAll(requires, module.autoRequiresBeans()); + Collections.addAll(requires, module.requiresPackagesFromType()); Arrays.stream(module.autoRequiresAspectBeans()) .map(AutoProvidesMojo::wrapAspect) .forEach(requires::add); From 8e5293066dbde41c2e1376bfdaed55302b1f1f7d Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Fri, 20 Jun 2025 16:21:09 -0400 Subject: [PATCH 4/9] separate generics in generated annotation --- .../io/avaje/inject/generator/ScopeInfo.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java index 9bcf9bddf..73e176f83 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java @@ -393,11 +393,41 @@ void buildAtInjectModule(Append writer) { writer.append(Constants.AT_GENERATED).eol(); writer.append("@InjectModule("); boolean leadingComma = false; - if (!provides.isEmpty()) { + List regularProvides = new ArrayList<>(); + List genericProvides = new ArrayList<>(); + + for (var type : provides) { + if (type.contains("<")) { + genericProvides.add(type); + } else { + regularProvides.add(type); + } + } + + if (!regularProvides.isEmpty()) { + attributeClasses(false, writer, "provides", provides); + leadingComma = true; + } + if (!genericProvides.isEmpty()) { attributeString(false, writer, "providesString", provides); leadingComma = true; } - if (!requires.isEmpty()) { + + List regularRequires = new ArrayList<>(); + List genericRequires = new ArrayList<>(); + + for (var type : requires) { + if (type.contains("<")) { + genericRequires.add(type); + } else { + regularRequires.add(type); + } + } + if (!regularRequires.isEmpty()) { + attributeClasses(leadingComma, writer, "requires", regularRequires); + leadingComma = true; + } + if (!genericRequires.isEmpty()) { attributeString(leadingComma, writer, "requiresString", requires); leadingComma = true; } @@ -430,7 +460,7 @@ private void attributeString( writer.append("}"); } - private void attributeClasses(boolean leadingComma, Append writer, String prefix, Set classNames) { + private void attributeClasses(boolean leadingComma, Append writer, String prefix, Collection classNames) { if (leadingComma) { writer.append(", "); } From cceec077ee2d6dfc9e7c8bc2299d86af9f129666 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Tue, 1 Jul 2025 08:58:53 -0400 Subject: [PATCH 5/9] Update AvajeModule.java Revert "Update AvajeModule.java" This reverts commit 87b41c2382366c323f9badf5a587ceaf869a6945. Update AvajeModule.java --- .../java/io/avaje/inject/spi/AvajeModule.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java index daab44d99..f73b87d7d 100644 --- a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java +++ b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java @@ -14,6 +14,17 @@ public interface AvajeModule extends InjectExtension { /** Empty array of strings. */ String[] EMPTY_STRINGS = {}; + /** + * Return public classes of the beans that would be registered by this module. + * + *

This method allows code to use reflection to inspect the modules classes before the module + * is wired. This method is not required for DI wiring. + */ + Class[] classes(); + + /** Build all the beans. */ + void build(Builder builder); + /** * Return the set of types this module explicitly provides to other modules. * @@ -150,17 +161,6 @@ default String[] autoRequiresAspectBeans() { .toArray(String[]::new); } - /** - * Return public classes of the beans that would be registered by this module. - * - *

This method allows code to use reflection to inspect the modules classes before the module - * is wired. This method is not required for DI wiring. - */ - Class[] classes(); - - /** Build all the beans. */ - void build(Builder builder); - /** Marker for custom scoped modules. */ interface Custom extends AvajeModule {} } From 8643d5e00cde9613140a3b5c7de5202729db3a3b Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Tue, 1 Jul 2025 20:21:18 -0400 Subject: [PATCH 6/9] merge requires/provides there is no reason to split into three separate methods --- .../inject/generator/ExternalProvider.java | 9 ++-- .../inject/generator/MetaDataOrdering.java | 11 +---- .../io/avaje/inject/generator/ScopeInfo.java | 30 +----------- .../inject/generator/SimpleModuleWriter.java | 40 +++++----------- .../avaje/inject/mojo/AutoProvidesMojo.java | 14 ++---- .../io/avaje/inject/DBeanScopeBuilder.java | 31 +++++------- .../java/io/avaje/inject/spi/AvajeModule.java | 48 ++++--------------- 7 files changed, 42 insertions(+), 141 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java index f159717a3..0ebdbf36b 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java @@ -85,9 +85,8 @@ static void registerModuleProvidedTypes(Set providedTypes) { final var name = module.getClass().getTypeName(); final var provides = new TreeSet(); Collections.addAll(provides, module.providesBeans()); - Collections.addAll(provides, module.autoProvidesBeans()); - for (final var provide : module.autoProvidesAspectBeans()) { - final var aspectType = Util.wrapAspect(provide); + for (final var provide : module.autoProvidesAspects()) { + final var aspectType = Util.wrapAspect(provide.getTypeName()); provides.add(aspectType); } registerExternalMetaData(name); @@ -95,9 +94,9 @@ static void registerModuleProvidedTypes(Set providedTypes) { providedTypes.addAll(provides); final List requires = new ArrayList<>(); Collections.addAll(requires, module.requiresBeans()); - Collections.addAll(requires, module.autoRequiresBeans()); Collections.addAll(requires, module.requiresPackagesFromType()); - Arrays.stream(module.autoRequiresAspectBeans()) + Arrays.stream(module.autoRequiresAspects()) + .map(Class::getTypeName) .map(Util::wrapAspect) .forEach(requires::add); diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java b/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java index d58fec9d7..4c6ee4784 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java @@ -25,7 +25,6 @@ final class MetaDataOrdering { private final List circularDependencies = new ArrayList<>(); private final Set missingDependencyTypes = new LinkedHashSet<>(); private final Set autoRequires = new TreeSet<>(); - private final Set autoRequiresAspects = new TreeSet<>(); MetaDataOrdering(Collection values, ScopeInfo scopeInfo) { this.scopeInfo = scopeInfo; @@ -224,11 +223,7 @@ private boolean dependencySatisfied(Dependency dependency, boolean includeExtern private boolean isExternal(String dependencyName, boolean includeExternal, MetaData queuedMeta) { if (includeExternal && externallyProvided(dependencyName)) { - if (Util.isAspectProvider(dependencyName)) { - autoRequiresAspects.add(Util.extractAspectType(dependencyName)); - } else { - autoRequires.add(dependencyName); - } + autoRequires.add(dependencyName); queuedMeta.markWithExternalDependency(dependencyName); return true; } @@ -239,10 +234,6 @@ Set autoRequires() { return autoRequires; } - Set autoRequiresAspects() { - return autoRequiresAspects; - } - List ordered() { return orderedList; } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java index 73e176f83..4a080851e 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java @@ -475,7 +475,7 @@ private void attributeClasses(boolean leadingComma, Append writer, String prefix writer.append("}"); } - void buildProvides(Append writer) { + void buildProvides(Append writer, Set provides, Set requires) { if (!provides.isEmpty()) { buildProvidesMethod(writer, "providesBeans", provides); } @@ -502,34 +502,6 @@ private void buildProvidesMethod(Append writer, String fieldName, Set ty writer.append(" }").eol().eol(); } - void buildAutoProvides(Append writer, Set autoProvides) { - autoProvides.removeAll(provides); - if (!autoProvides.isEmpty()) { - buildProvidesMethod(writer, "autoProvidesBeans", autoProvides); - } - } - - void buildAutoProvidesAspects(Append writer, Set autoProvidesAspects) { - autoProvidesAspects.removeAll(provides); - if (!autoProvidesAspects.isEmpty()) { - buildProvidesMethod(writer, "autoProvidesAspectBeans", autoProvidesAspects); - } - } - - void buildAutoRequires(Append writer, Set autoRequires) { - autoRequires.removeAll(requires); - if (!autoRequires.isEmpty()) { - buildProvidesMethod(writer, "autoRequiresBeans", autoRequires); - } - } - - void buildAutoRequiresAspects(Append writer, Set autoRequires) { - autoRequires.removeAll(requires); - if (!autoRequires.isEmpty()) { - buildProvidesMethod(writer, "autoRequiresAspectBeans", autoRequires); - } - } - void readModuleMetaData(TypeElement moduleType) { final InjectModulePrism module = InjectModulePrism.getInstanceOn(moduleType); final String name = module == null ? null : module.name(); diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java index 13b1dbf94..568d341a6 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java @@ -96,9 +96,9 @@ void write() throws IOException { } else { writeRequiredModules(); } + writeBuildMethod(); writeProvides(); writeClassesMethod(); - writeBuildMethod(); writeBuildMethods(); writeEndClass(); writer.close(); @@ -188,45 +188,28 @@ private void writeServicesFile(ScopeInfo.Type scopeType) { } private void writeProvides() { - final Set autoProvidesAspects = new TreeSet<>(); - final Set autoProvides = new TreeSet<>(); + final Set scopeProvides = new TreeSet<>(scopeInfo.provides()); if (scopeType == ScopeInfo.Type.CUSTOM) { - autoProvides.add(scopeInfo.scopeAnnotationFQN()); - autoProvides.add(shortName); + scopeProvides.add(scopeInfo.scopeAnnotationFQN()); + scopeProvides.add(shortName); } - for (MetaData metaData : ordering.ordered()) { final String aspect = metaData.providesAspect(); if (aspect != null && !aspect.isEmpty()) { - autoProvidesAspects.add(aspect); + scopeProvides.add(Util.wrapAspect(aspect)); } final var forExternal = metaData.autoProvides(); if (forExternal != null && !forExternal.isEmpty()) { - autoProvides.addAll(forExternal); + scopeProvides.addAll(forExternal); } } - if (!autoProvides.isEmpty()) { - scopeInfo.buildAutoProvides(writer, autoProvides); - } - if (!autoProvidesAspects.isEmpty()) { - scopeInfo.buildAutoProvidesAspects(writer, autoProvidesAspects); - } - Set autoRequires = ordering.autoRequires(); - if (!autoRequires.isEmpty()) { - scopeInfo.buildAutoRequires(writer, autoRequires); - } - Set autoRequiresAspects = ordering.autoRequiresAspects(); - if (!autoRequiresAspects.isEmpty()) { - scopeInfo.buildAutoRequiresAspects(writer, autoRequiresAspects); - } + Set scopeRequires = new TreeSet<>(scopeInfo.requires()); + scopeRequires.addAll(ordering.autoRequires()); + scopeInfo.buildProvides(writer, scopeProvides, scopeRequires); - var requires = new ArrayList<>(scopeInfo.requires()); - var provides = new ArrayList<>(scopeInfo.provides()); - requires.addAll(autoRequires); - autoRequiresAspects.stream().map(Util::wrapAspect).forEach(requires::add); - provides.addAll(autoProvides); - autoProvidesAspects.stream().map(Util::wrapAspect).forEach(provides::add); + var requires = new ArrayList<>(scopeRequires); + var provides = new ArrayList<>(scopeProvides); ProcessingContext.addModule(new ModuleData(fullName, provides, requires)); } @@ -320,7 +303,6 @@ private void writeStartClass() { if (scopeInfo.addModuleConstructor()) { writeConstructor(); } - scopeInfo.buildProvides(writer); } private void writeWithBeans() { diff --git a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java index 7a8e3d4de..2afd9d3b9 100644 --- a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java +++ b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java @@ -147,21 +147,15 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) provides.add(type); } - for (final var provide : module.autoProvidesBeans()) { - var type = provide; - provides.add(type); - } - - for (final var provide : module.autoProvidesAspectBeans()) { - var type = wrapAspect(provide); + for (final var provide : module.autoProvidesAspects()) { + var type = wrapAspect(provide.getTypeName()); provides.add(type); } final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); - - Collections.addAll(requires, module.autoRequiresBeans()); Collections.addAll(requires, module.requiresPackagesFromType()); - Arrays.stream(module.autoRequiresAspectBeans()) + Arrays.stream(module.autoRequiresAspects()) + .map(Class::getTypeName) .map(AutoProvidesMojo::wrapAspect) .forEach(requires::add); modules.add(new ModuleData(name.getTypeName(), provides, requires)); diff --git a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java index a8261d449..2c3eb1bc7 100644 --- a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java +++ b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java @@ -327,8 +327,7 @@ public void add(AvajeModule module) { .add(factoryState); addFactoryProvides(factoryState, module.providesBeans()); - addFactoryProvides(factoryState, module.autoProvidesBeans()); - addFactoryProvides(factoryState, module.autoProvidesAspectBeans()); + addAspectProvides(factoryState, module.autoProvidesAspects()); if (factoryState.isRequiresEmpty()) { if (factoryState.explicitlyProvides()) { @@ -344,6 +343,16 @@ public void add(AvajeModule module) { } } + private void addAspectProvides(FactoryState factoryState, Class[] aspects) { + for (final var feature : aspects) { + providesMap + .computeIfAbsent( + "io.avaje.inject.aop.AspectProvider<" + feature.getTypeName() + ">", + s -> new FactoryList()) + .add(factoryState); + } + } + private void addFactoryProvides(FactoryState factoryState, String[] provides) { for (final var feature : provides) { providesMap.computeIfAbsent(feature, s -> new FactoryList()).add(factoryState); @@ -392,7 +401,6 @@ private void processQueue() { sb.append("Module [").append(factory).append("] has unsatisfied"); unsatisfiedRequires(sb, factory.requires(), "requires"); unsatisfiedRequires(sb, factory.requiresPackages(), "requiresPackages"); - unsatisfiedRequires(sb, factory.autoRequires(), "autoRequires"); } sb.append(" - none of the loaded modules ").append(moduleNames).append(" have this in their @InjectModule( provides = ... ). "); if (parent != null) { @@ -442,9 +450,7 @@ private int processQueuedFactories() { /** Return true if the (module) requires dependencies are satisfied for this factory. */ private boolean satisfiedDependencies(FactoryState factory) { return satisfiedDependencies(factory.requires()) - && satisfiedDependencies(factory.requiresPackages()) - && satisfiedDependencies(factory.autoRequiresAspects()) - && satisfiedDependencies(factory.autoRequires()); + && satisfiedDependencies(factory.requiresPackages()); } private boolean satisfiedDependencies(String[] requires) { @@ -493,24 +499,13 @@ String[] requiresPackages() { return factory.requiresPackagesFromType(); } - String[] autoRequires() { - return factory.autoRequiresBeans(); - } - - String[] autoRequiresAspects() { - return factory.autoRequiresAspectBeans(); - } - @Override public String toString() { return factory.getClass().getTypeName(); } boolean isRequiresEmpty() { - return isEmpty(factory.requiresBeans()) - && isEmpty(factory.requiresPackagesFromType()) - && isEmpty(factory.autoRequiresBeans()) - && isEmpty(factory.autoRequiresAspectBeans()); + return isEmpty(factory.requiresBeans()) && isEmpty(factory.requiresPackagesFromType()); } boolean explicitlyProvides() { diff --git a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java index f73b87d7d..ee86d22b3 100644 --- a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java +++ b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java @@ -3,6 +3,7 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Objects; +import java.util.stream.Stream; /** A Module containing dependencies that will be included in BeanScope. */ public interface AvajeModule extends InjectExtension { @@ -37,7 +38,9 @@ default Type[] provides() { /** Return the type names of types this module explicitly provides to other modules. */ default String[] providesBeans() { - return Arrays.stream(Objects.requireNonNullElse(provides(), EMPTY_CLASSES)) + return Stream.concat( + Arrays.stream(Objects.requireNonNullElse(provides(), EMPTY_CLASSES)), + Arrays.stream(Objects.requireNonNullElse(autoProvides(), EMPTY_CLASSES))) .map(Type::getTypeName) .toArray(String[]::new); } @@ -57,7 +60,9 @@ default Type[] requires() { * modules. */ default String[] requiresBeans() { - return Arrays.stream(Objects.requireNonNullElse(requires(), EMPTY_CLASSES)) + return Stream.concat( + Arrays.stream(Objects.requireNonNullElse(requires(), EMPTY_CLASSES)), + Arrays.stream(Objects.requireNonNullElse(autoRequires(), EMPTY_CLASSES))) .map(Type::getTypeName) .toArray(String[]::new); } @@ -85,23 +90,13 @@ default String[] requiresPackagesFromType() { *

This is a convenience when using multiple modules that is otherwise controlled manually by * explicitly using {@link AvajeModule#provides()}. * - * @deprecated use {@link #autoProvidesBeans()} + * @deprecated use {@link #providesBeans()} */ @Deprecated(forRemoval = true) default Type[] autoProvides() { return EMPTY_CLASSES; } - /** - * Return the type names of classes that this module provides that we allow other modules to auto - * depend on. - */ - default String[] autoProvidesBeans() { - return Arrays.stream(Objects.requireNonNullElse(autoProvides(), EMPTY_CLASSES)) - .map(Type::getTypeName) - .toArray(String[]::new); - } - /** * Return the aspects that this module provides. * @@ -113,13 +108,6 @@ default Class[] autoProvidesAspects() { return EMPTY_CLASSES; } - /** Return the type names of aspects that this module provides. */ - default String[] autoProvidesAspectBeans() { - return Arrays.stream(Objects.requireNonNullElse(autoProvidesAspects(), EMPTY_CLASSES)) - .map(Class::getTypeName) - .toArray(String[]::new); - } - /** * These are the classes that this module requires for wiring that are provided by other external * modules (that are in the classpath at compile time). @@ -132,16 +120,6 @@ default Type[] autoRequires() { return EMPTY_CLASSES; } - /** - * Return the type names of classes that this module requires for wiring that are provided by - * other external modules. - */ - default String[] autoRequiresBeans() { - return Arrays.stream(Objects.requireNonNullElse(autoRequires(), EMPTY_CLASSES)) - .map(Type::getTypeName) - .toArray(String[]::new); - } - /** * These are the aspects that this module requires whose implementations are provided by other * external modules (that are in the classpath at compile time). @@ -151,16 +129,6 @@ default Class[] autoRequiresAspects() { return EMPTY_CLASSES; } - /** - * Return the type names of aspects that this module requires whose implementations are provided - * by other external modules. - */ - default String[] autoRequiresAspectBeans() { - return Arrays.stream(Objects.requireNonNullElse(autoRequiresAspects(), EMPTY_CLASSES)) - .map(Class::getTypeName) - .toArray(String[]::new); - } - /** Marker for custom scoped modules. */ interface Custom extends AvajeModule {} } From 8799e14dbae9a629ac82b8daf1517e9fb4e7d5a9 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Tue, 1 Jul 2025 20:40:06 -0400 Subject: [PATCH 7/9] gradle plugin --- inject-gradle-plugin/build.gradle | 4 ++-- .../io/avaje/inject/plugin/AvajeInjectPlugin.java | 15 +++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/inject-gradle-plugin/build.gradle b/inject-gradle-plugin/build.gradle index f36c44a60..c48d22706 100644 --- a/inject-gradle-plugin/build.gradle +++ b/inject-gradle-plugin/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'io.avaje.inject' -version '11.1' +version '11.6-RC4' repositories { mavenLocal() @@ -14,7 +14,7 @@ repositories { } dependencies { - implementation 'io.avaje:avaje-inject:11.1' + implementation 'io.avaje:avaje-inject:11.6-RC4' implementation gradleApi() testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' diff --git a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java index bab001186..22a7707a9 100644 --- a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java +++ b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java @@ -78,7 +78,7 @@ private void writeProvidedPlugins(ClassLoader classLoader, FileWriter pluginWrit provides.add(provide); } for (final var provide : plugin.providesAspectBeans()) { - provides.add(wrapAspect(provide.getCanonicalName())); + provides.add(wrapAspect(provide)); } pluginEntries.put(typeName, provides); } @@ -133,20 +133,11 @@ private void writeModuleCSV(ClassLoader classLoader, FileWriter moduleWriter) th var type = provide; provides.add(type); } - for (final var provide : module.autoProvidesBeans()) { - var type = provide; - provides.add(type); - } - for (final var provide : module.autoprovidesAspectBeans()) { - var type = wrapAspect(provide); - provides.add(type); - } final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); - - Arrays.stream(module.autoRequires()).forEach(requires::add); - Arrays.stream(module.requiresPackages()).forEach(requires::add); + Collections.addAll(requires, module.requiresPackagesFromType()); Arrays.stream(module.autoRequiresAspects()) + .map(Class::getTypeName) .map(AvajeInjectPlugin::wrapAspect) .forEach(requires::add); modules.add(new ModuleData(name, provides, requires)); From 06a88a7ad4a20c682ecc1534c9767f203e0339ac Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Tue, 1 Jul 2025 22:28:17 -0400 Subject: [PATCH 8/9] plugin should remain unchanged --- .../inject/generator/ExternalProvider.java | 8 ++--- .../inject/plugin/AvajeInjectPlugin.java | 15 ++++---- .../avaje/inject/mojo/AutoProvidesMojo.java | 4 ++- .../io/avaje/inject/spi/InjectPlugin.java | 34 ++++++++----------- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java index 0ebdbf36b..a5ef7b85b 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java @@ -124,11 +124,11 @@ static void registerPluginProvidedTypes(ScopeInfo defaultScope) { continue; } APContext.logNote("Loaded Plugin: %s", plugin.getClass().getTypeName()); - for (final var provide : plugin.providesBeans()) { - defaultScope.pluginProvided(provide); + for (final var provide : plugin.provides()) { + defaultScope.pluginProvided(provide.getTypeName()); } - for (final var provide : plugin.providesAspectBeans()) { - defaultScope.pluginProvided(Util.wrapAspect(provide)); + for (final var provide : plugin.providesAspects()) { + defaultScope.pluginProvided(Util.wrapAspect(provide.getTypeName())); } } } diff --git a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java index 22a7707a9..c497959af 100644 --- a/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java +++ b/inject-gradle-plugin/src/main/java/io/avaje/inject/plugin/AvajeInjectPlugin.java @@ -49,8 +49,8 @@ private void writeProvides(Project project) { try (var classLoader = classLoader(project); var pluginWriter = createFileWriter(outputDir.getPath(), "avaje-plugins.csv"); var moduleCSV = createFileWriter(outputDir.getPath(), "avaje-module-dependencies.csv")) { - writeProvidedPlugins(classLoader, pluginWriter); - writeModuleCSV(classLoader, moduleCSV); + writeProvidedPlugins(classLoader, pluginWriter); + writeModuleCSV(classLoader, moduleCSV); } catch (IOException e) { throw new GradleException("Failed to write avaje-module-provides", e); } @@ -74,11 +74,11 @@ private void writeProvidedPlugins(ClassLoader classLoader, FileWriter pluginWrit final List provides = new ArrayList<>(); final var typeName = plugin.getClass().getTypeName(); System.out.println("Loaded Plugin: " + typeName); - for (final var provide : plugin.providesBeans()) { - provides.add(provide); + for (final var provide : plugin.provides()) { + provides.add(provide.getTypeName()); } - for (final var provide : plugin.providesAspectBeans()) { - provides.add(wrapAspect(provide)); + for (final var provide : plugin.providesAspects()) { + provides.add(wrapAspect(provide.getCanonicalName())); } pluginEntries.put(typeName, provides); } @@ -104,7 +104,8 @@ private URLClassLoader classLoader(Project project) { private static URL[] createClassPath(Project project) { try { - Set compileClasspath = project.getConfigurations().getByName("compileClasspath").resolve(); + Set compileClasspath = + project.getConfigurations().getByName("compileClasspath").resolve(); final List urls = new ArrayList<>(compileClasspath.size()); for (File file : compileClasspath) { urls.add(file.toURI().toURL()); diff --git a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java index 2afd9d3b9..0997845cf 100644 --- a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java +++ b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java @@ -109,7 +109,9 @@ private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter plug final List provides = new ArrayList<>(); final var typeName = plugin.getClass(); log.info("Loaded Plugin: " + typeName); - Collections.addAll(provides, plugin.providesBeans()); + for (final var provide : plugin.provides()) { + provides.add(provide.getTypeName()); + } for (final var provide : plugin.providesAspects()) { provides.add(wrapAspect(provide.getCanonicalName())); } diff --git a/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java b/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java index 103ba7412..3677b88a7 100644 --- a/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java +++ b/inject/src/main/java/io/avaje/inject/spi/InjectPlugin.java @@ -1,10 +1,9 @@ package io.avaje.inject.spi; -import java.lang.reflect.Type; -import java.util.Arrays; - import io.avaje.inject.BeanScopeBuilder; +import java.lang.reflect.Type; + /** * A Plugin that can be applied when creating a bean scope. * @@ -13,32 +12,27 @@ */ public interface InjectPlugin extends InjectExtension { - /** Empty array of classes. */ + /** + * Empty array of classes. + */ Class[] EMPTY_CLASSES = {}; - /** Empty array of classes. */ - String[] EMPTY_STRINGS = {}; - - /** Apply the plugin to the scope builder. */ + /** + * Apply the plugin to the scope builder. + */ void apply(BeanScopeBuilder builder); - /** Return the classes that the plugin provides. */ + /** + * Return the classes that the plugin provides. + */ default Type[] provides() { return EMPTY_CLASSES; } - /** Return the type names of types this module explicitly provides to other modules. */ - default String[] providesBeans() { - return Arrays.stream(provides()).map(Type::getTypeName).toArray(String[]::new); - } - - /** Return the aspect classes that the plugin provides. */ + /** + * Return the aspect classes that the plugin provides. + */ default Class[] providesAspects() { return EMPTY_CLASSES; } - - /** Return the type names of types this module explicitly provides to other modules. */ - default String[] providesAspectBeans() { - return Arrays.stream(providesAspects()).map(Type::getTypeName).toArray(String[]::new); - } } From d164fba17ae5694cd4b9137b6613fe958f9dba4b Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Wed, 2 Jul 2025 07:51:50 -0400 Subject: [PATCH 9/9] Revert "merge requires/provides" This reverts commit 8643d5e00cde9613140a3b5c7de5202729db3a3b. --- .../inject/generator/ExternalProvider.java | 9 ++-- .../inject/generator/MetaDataOrdering.java | 11 ++++- .../io/avaje/inject/generator/ScopeInfo.java | 30 +++++++++++- .../inject/generator/SimpleModuleWriter.java | 40 +++++++++++----- .../avaje/inject/mojo/AutoProvidesMojo.java | 14 ++++-- .../io/avaje/inject/DBeanScopeBuilder.java | 31 +++++++----- .../java/io/avaje/inject/spi/AvajeModule.java | 48 +++++++++++++++---- 7 files changed, 141 insertions(+), 42 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java index a5ef7b85b..1415c2e04 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ExternalProvider.java @@ -85,8 +85,9 @@ static void registerModuleProvidedTypes(Set providedTypes) { final var name = module.getClass().getTypeName(); final var provides = new TreeSet(); Collections.addAll(provides, module.providesBeans()); - for (final var provide : module.autoProvidesAspects()) { - final var aspectType = Util.wrapAspect(provide.getTypeName()); + Collections.addAll(provides, module.autoProvidesBeans()); + for (final var provide : module.autoProvidesAspectBeans()) { + final var aspectType = Util.wrapAspect(provide); provides.add(aspectType); } registerExternalMetaData(name); @@ -94,9 +95,9 @@ static void registerModuleProvidedTypes(Set providedTypes) { providedTypes.addAll(provides); final List requires = new ArrayList<>(); Collections.addAll(requires, module.requiresBeans()); + Collections.addAll(requires, module.autoRequiresBeans()); Collections.addAll(requires, module.requiresPackagesFromType()); - Arrays.stream(module.autoRequiresAspects()) - .map(Class::getTypeName) + Arrays.stream(module.autoRequiresAspectBeans()) .map(Util::wrapAspect) .forEach(requires::add); diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java b/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java index 4c6ee4784..d58fec9d7 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MetaDataOrdering.java @@ -25,6 +25,7 @@ final class MetaDataOrdering { private final List circularDependencies = new ArrayList<>(); private final Set missingDependencyTypes = new LinkedHashSet<>(); private final Set autoRequires = new TreeSet<>(); + private final Set autoRequiresAspects = new TreeSet<>(); MetaDataOrdering(Collection values, ScopeInfo scopeInfo) { this.scopeInfo = scopeInfo; @@ -223,7 +224,11 @@ private boolean dependencySatisfied(Dependency dependency, boolean includeExtern private boolean isExternal(String dependencyName, boolean includeExternal, MetaData queuedMeta) { if (includeExternal && externallyProvided(dependencyName)) { - autoRequires.add(dependencyName); + if (Util.isAspectProvider(dependencyName)) { + autoRequiresAspects.add(Util.extractAspectType(dependencyName)); + } else { + autoRequires.add(dependencyName); + } queuedMeta.markWithExternalDependency(dependencyName); return true; } @@ -234,6 +239,10 @@ Set autoRequires() { return autoRequires; } + Set autoRequiresAspects() { + return autoRequiresAspects; + } + List ordered() { return orderedList; } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java index 4a080851e..73e176f83 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/ScopeInfo.java @@ -475,7 +475,7 @@ private void attributeClasses(boolean leadingComma, Append writer, String prefix writer.append("}"); } - void buildProvides(Append writer, Set provides, Set requires) { + void buildProvides(Append writer) { if (!provides.isEmpty()) { buildProvidesMethod(writer, "providesBeans", provides); } @@ -502,6 +502,34 @@ private void buildProvidesMethod(Append writer, String fieldName, Set ty writer.append(" }").eol().eol(); } + void buildAutoProvides(Append writer, Set autoProvides) { + autoProvides.removeAll(provides); + if (!autoProvides.isEmpty()) { + buildProvidesMethod(writer, "autoProvidesBeans", autoProvides); + } + } + + void buildAutoProvidesAspects(Append writer, Set autoProvidesAspects) { + autoProvidesAspects.removeAll(provides); + if (!autoProvidesAspects.isEmpty()) { + buildProvidesMethod(writer, "autoProvidesAspectBeans", autoProvidesAspects); + } + } + + void buildAutoRequires(Append writer, Set autoRequires) { + autoRequires.removeAll(requires); + if (!autoRequires.isEmpty()) { + buildProvidesMethod(writer, "autoRequiresBeans", autoRequires); + } + } + + void buildAutoRequiresAspects(Append writer, Set autoRequires) { + autoRequires.removeAll(requires); + if (!autoRequires.isEmpty()) { + buildProvidesMethod(writer, "autoRequiresAspectBeans", autoRequires); + } + } + void readModuleMetaData(TypeElement moduleType) { final InjectModulePrism module = InjectModulePrism.getInstanceOn(moduleType); final String name = module == null ? null : module.name(); diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java index 568d341a6..13b1dbf94 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleModuleWriter.java @@ -96,9 +96,9 @@ void write() throws IOException { } else { writeRequiredModules(); } - writeBuildMethod(); writeProvides(); writeClassesMethod(); + writeBuildMethod(); writeBuildMethods(); writeEndClass(); writer.close(); @@ -188,28 +188,45 @@ private void writeServicesFile(ScopeInfo.Type scopeType) { } private void writeProvides() { - final Set scopeProvides = new TreeSet<>(scopeInfo.provides()); + final Set autoProvidesAspects = new TreeSet<>(); + final Set autoProvides = new TreeSet<>(); if (scopeType == ScopeInfo.Type.CUSTOM) { - scopeProvides.add(scopeInfo.scopeAnnotationFQN()); - scopeProvides.add(shortName); + autoProvides.add(scopeInfo.scopeAnnotationFQN()); + autoProvides.add(shortName); } + for (MetaData metaData : ordering.ordered()) { final String aspect = metaData.providesAspect(); if (aspect != null && !aspect.isEmpty()) { - scopeProvides.add(Util.wrapAspect(aspect)); + autoProvidesAspects.add(aspect); } final var forExternal = metaData.autoProvides(); if (forExternal != null && !forExternal.isEmpty()) { - scopeProvides.addAll(forExternal); + autoProvides.addAll(forExternal); } } - Set scopeRequires = new TreeSet<>(scopeInfo.requires()); - scopeRequires.addAll(ordering.autoRequires()); - scopeInfo.buildProvides(writer, scopeProvides, scopeRequires); + if (!autoProvides.isEmpty()) { + scopeInfo.buildAutoProvides(writer, autoProvides); + } + if (!autoProvidesAspects.isEmpty()) { + scopeInfo.buildAutoProvidesAspects(writer, autoProvidesAspects); + } + Set autoRequires = ordering.autoRequires(); + if (!autoRequires.isEmpty()) { + scopeInfo.buildAutoRequires(writer, autoRequires); + } + Set autoRequiresAspects = ordering.autoRequiresAspects(); + if (!autoRequiresAspects.isEmpty()) { + scopeInfo.buildAutoRequiresAspects(writer, autoRequiresAspects); + } - var requires = new ArrayList<>(scopeRequires); - var provides = new ArrayList<>(scopeProvides); + var requires = new ArrayList<>(scopeInfo.requires()); + var provides = new ArrayList<>(scopeInfo.provides()); + requires.addAll(autoRequires); + autoRequiresAspects.stream().map(Util::wrapAspect).forEach(requires::add); + provides.addAll(autoProvides); + autoProvidesAspects.stream().map(Util::wrapAspect).forEach(provides::add); ProcessingContext.addModule(new ModuleData(fullName, provides, requires)); } @@ -303,6 +320,7 @@ private void writeStartClass() { if (scopeInfo.addModuleConstructor()) { writeConstructor(); } + scopeInfo.buildProvides(writer); } private void writeWithBeans() { diff --git a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java index 0997845cf..55e0b0775 100644 --- a/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java +++ b/inject-maven-plugin/src/main/java/io/avaje/inject/mojo/AutoProvidesMojo.java @@ -149,15 +149,21 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) provides.add(type); } - for (final var provide : module.autoProvidesAspects()) { - var type = wrapAspect(provide.getTypeName()); + for (final var provide : module.autoProvidesBeans()) { + var type = provide; + provides.add(type); + } + + for (final var provide : module.autoProvidesAspectBeans()) { + var type = wrapAspect(provide); provides.add(type); } final var requires = Arrays.stream(module.requiresBeans()).collect(toList()); + + Collections.addAll(requires, module.autoRequiresBeans()); Collections.addAll(requires, module.requiresPackagesFromType()); - Arrays.stream(module.autoRequiresAspects()) - .map(Class::getTypeName) + Arrays.stream(module.autoRequiresAspectBeans()) .map(AutoProvidesMojo::wrapAspect) .forEach(requires::add); modules.add(new ModuleData(name.getTypeName(), provides, requires)); diff --git a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java index 2c3eb1bc7..a8261d449 100644 --- a/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java +++ b/inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java @@ -327,7 +327,8 @@ public void add(AvajeModule module) { .add(factoryState); addFactoryProvides(factoryState, module.providesBeans()); - addAspectProvides(factoryState, module.autoProvidesAspects()); + addFactoryProvides(factoryState, module.autoProvidesBeans()); + addFactoryProvides(factoryState, module.autoProvidesAspectBeans()); if (factoryState.isRequiresEmpty()) { if (factoryState.explicitlyProvides()) { @@ -343,16 +344,6 @@ public void add(AvajeModule module) { } } - private void addAspectProvides(FactoryState factoryState, Class[] aspects) { - for (final var feature : aspects) { - providesMap - .computeIfAbsent( - "io.avaje.inject.aop.AspectProvider<" + feature.getTypeName() + ">", - s -> new FactoryList()) - .add(factoryState); - } - } - private void addFactoryProvides(FactoryState factoryState, String[] provides) { for (final var feature : provides) { providesMap.computeIfAbsent(feature, s -> new FactoryList()).add(factoryState); @@ -401,6 +392,7 @@ private void processQueue() { sb.append("Module [").append(factory).append("] has unsatisfied"); unsatisfiedRequires(sb, factory.requires(), "requires"); unsatisfiedRequires(sb, factory.requiresPackages(), "requiresPackages"); + unsatisfiedRequires(sb, factory.autoRequires(), "autoRequires"); } sb.append(" - none of the loaded modules ").append(moduleNames).append(" have this in their @InjectModule( provides = ... ). "); if (parent != null) { @@ -450,7 +442,9 @@ private int processQueuedFactories() { /** Return true if the (module) requires dependencies are satisfied for this factory. */ private boolean satisfiedDependencies(FactoryState factory) { return satisfiedDependencies(factory.requires()) - && satisfiedDependencies(factory.requiresPackages()); + && satisfiedDependencies(factory.requiresPackages()) + && satisfiedDependencies(factory.autoRequiresAspects()) + && satisfiedDependencies(factory.autoRequires()); } private boolean satisfiedDependencies(String[] requires) { @@ -499,13 +493,24 @@ String[] requiresPackages() { return factory.requiresPackagesFromType(); } + String[] autoRequires() { + return factory.autoRequiresBeans(); + } + + String[] autoRequiresAspects() { + return factory.autoRequiresAspectBeans(); + } + @Override public String toString() { return factory.getClass().getTypeName(); } boolean isRequiresEmpty() { - return isEmpty(factory.requiresBeans()) && isEmpty(factory.requiresPackagesFromType()); + return isEmpty(factory.requiresBeans()) + && isEmpty(factory.requiresPackagesFromType()) + && isEmpty(factory.autoRequiresBeans()) + && isEmpty(factory.autoRequiresAspectBeans()); } boolean explicitlyProvides() { diff --git a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java index ee86d22b3..f73b87d7d 100644 --- a/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java +++ b/inject/src/main/java/io/avaje/inject/spi/AvajeModule.java @@ -3,7 +3,6 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Objects; -import java.util.stream.Stream; /** A Module containing dependencies that will be included in BeanScope. */ public interface AvajeModule extends InjectExtension { @@ -38,9 +37,7 @@ default Type[] provides() { /** Return the type names of types this module explicitly provides to other modules. */ default String[] providesBeans() { - return Stream.concat( - Arrays.stream(Objects.requireNonNullElse(provides(), EMPTY_CLASSES)), - Arrays.stream(Objects.requireNonNullElse(autoProvides(), EMPTY_CLASSES))) + return Arrays.stream(Objects.requireNonNullElse(provides(), EMPTY_CLASSES)) .map(Type::getTypeName) .toArray(String[]::new); } @@ -60,9 +57,7 @@ default Type[] requires() { * modules. */ default String[] requiresBeans() { - return Stream.concat( - Arrays.stream(Objects.requireNonNullElse(requires(), EMPTY_CLASSES)), - Arrays.stream(Objects.requireNonNullElse(autoRequires(), EMPTY_CLASSES))) + return Arrays.stream(Objects.requireNonNullElse(requires(), EMPTY_CLASSES)) .map(Type::getTypeName) .toArray(String[]::new); } @@ -90,13 +85,23 @@ default String[] requiresPackagesFromType() { *

This is a convenience when using multiple modules that is otherwise controlled manually by * explicitly using {@link AvajeModule#provides()}. * - * @deprecated use {@link #providesBeans()} + * @deprecated use {@link #autoProvidesBeans()} */ @Deprecated(forRemoval = true) default Type[] autoProvides() { return EMPTY_CLASSES; } + /** + * Return the type names of classes that this module provides that we allow other modules to auto + * depend on. + */ + default String[] autoProvidesBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoProvides(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * Return the aspects that this module provides. * @@ -108,6 +113,13 @@ default Class[] autoProvidesAspects() { return EMPTY_CLASSES; } + /** Return the type names of aspects that this module provides. */ + default String[] autoProvidesAspectBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoProvidesAspects(), EMPTY_CLASSES)) + .map(Class::getTypeName) + .toArray(String[]::new); + } + /** * These are the classes that this module requires for wiring that are provided by other external * modules (that are in the classpath at compile time). @@ -120,6 +132,16 @@ default Type[] autoRequires() { return EMPTY_CLASSES; } + /** + * Return the type names of classes that this module requires for wiring that are provided by + * other external modules. + */ + default String[] autoRequiresBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoRequires(), EMPTY_CLASSES)) + .map(Type::getTypeName) + .toArray(String[]::new); + } + /** * These are the aspects that this module requires whose implementations are provided by other * external modules (that are in the classpath at compile time). @@ -129,6 +151,16 @@ default Class[] autoRequiresAspects() { return EMPTY_CLASSES; } + /** + * Return the type names of aspects that this module requires whose implementations are provided + * by other external modules. + */ + default String[] autoRequiresAspectBeans() { + return Arrays.stream(Objects.requireNonNullElse(autoRequiresAspects(), EMPTY_CLASSES)) + .map(Class::getTypeName) + .toArray(String[]::new); + } + /** Marker for custom scoped modules. */ interface Custom extends AvajeModule {} }