Skip to content

Merge Detected Services into META-INF #733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -81,7 +82,6 @@ static void registerModuleProvidedTypes(Set<String> providedTypes) {
}
for (final var module : modules) {
final var name = module.getClass().getTypeName();
APContext.logNote("Detected Module: %s", name);
final var provides = new TreeSet<String>();
for (final var provide : module.provides()) {
provides.add(provide.getTypeName());
Expand Down Expand Up @@ -120,6 +120,7 @@ static void registerPluginProvidedTypes(ScopeInfo defaultScope) {

List<InjectPlugin> plugins = LoadServices.loadPlugins(CLASS_LOADER);
for (final var plugin : plugins) {
ProcessingContext.addExternalInjectSPI(plugin.getClass().getCanonicalName());
var name = plugin.getClass().getTypeName();
if (avajePlugins.containsKey(name)) {
continue;
Expand All @@ -143,6 +144,7 @@ private static boolean pluginExists(String relativeName) {
}

static void registerExternalMetaData(String name) {
ProcessingContext.addExternalInjectSPI(name);
Optional.ofNullable(APContext.typeElement(name))
.map(TypeElement::getEnclosedElements)
.map(ElementFilter::methodsIn)
Expand All @@ -164,10 +166,13 @@ static void readMetaDataProvides(Collection<String> providedTypes) {
}

static void scanAllInjectPlugins(ScopeInfo defaultScope) {
Map<String, List<String>> plugins = new HashMap<>();
final var hasPlugins = !defaultScope.pluginProvided().isEmpty();
avajePlugins.forEach((k, v) -> {
if (APContext.typeElement(k) != null) {
plugins.put(k, v);
APContext.logNote("Loaded Plugin: %s", k);
ProcessingContext.addExternalInjectSPI(k);
v.forEach(defaultScope::pluginProvided);
}
});
Expand All @@ -179,42 +184,50 @@ static void scanAllInjectPlugins(ScopeInfo defaultScope) {
injectExtensions()
.filter(PluginProvidesPrism::isPresent)
.distinct()
.forEach(pluginType -> addPluginToScope(defaultScope, pluginType));
.forEach(pluginType -> addPluginToScope(defaultScope, pluginType, plugins));

if (defaultScope.pluginProvided().isEmpty()) {
APContext.logNote("No external plugins detected");
}
writePluginProvides(defaultScope);
writePluginProvides(plugins);
}

private static void writePluginProvides(ScopeInfo defaultScope) {
private static void writePluginProvides(Map<String, List<String>> plugins) {
// write detected plugins to a text file for test compilation
try (final var pluginWriter = new FileWriter(APContext.getBuildResource("avaje-plugin-provides.txt").toFile())) {
for (var providedType : defaultScope.pluginProvided()) {
pluginWriter.write(providedType);
try (final var pluginWriter = new FileWriter(APContext.getBuildResource("avaje-plugins.csv").toFile())) {
pluginWriter.write("External Plugin Type|Provides");
for (final var plugin : plugins.entrySet()) {
pluginWriter.write("\n");
pluginWriter.write(plugin.getKey());
pluginWriter.write("|");
var provides = String.join(",", plugin.getValue());
pluginWriter.write(provides.isEmpty() ? " " : provides);
}
} catch (IOException e) {
APContext.logWarn("Failed to write avaje-plugin-provides.txt due to %s", e.getMessage());
APContext.logWarn("Failed to write avaje-plugins.csv due to %s", e.getMessage());
}
}

private static void addPluginToScope(ScopeInfo defaultScope, TypeElement pluginType) {
private static void addPluginToScope(ScopeInfo defaultScope, TypeElement pluginType, Map<String, List<String>> plugins) {
final var name = pluginType.getQualifiedName().toString();
if (avajePlugins.containsKey(name)) {
return;
}
ProcessingContext.addExternalInjectSPI(name);
var prism = PluginProvidesPrism.getInstanceOn(pluginType);
List<String> provides = new ArrayList<>();
for (final var provide : prism.value()) {
defaultScope.pluginProvided(provide.toString());
provides.add(provide.toString());
}
for (final var provide : prism.providesStrings()) {
defaultScope.pluginProvided(provide);
provides.add(provide);
}
for (final var provide : prism.providesAspects()) {
defaultScope.pluginProvided(Util.wrapAspect(provide.toString()));
final var wrapAspect = Util.wrapAspect(provide.toString());
defaultScope.pluginProvided(wrapAspect);
provides.add(wrapAspect);
}
APContext.logNote("Loaded Plugin: %s", name);
plugins.put(name, provides);
}

static void scanAllAvajeModules(Collection<String> providedTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
Expand All @@ -29,6 +28,7 @@
@GenerateUtils
@GenerateAPContext
@GenerateModuleInfoReader
@SupportedOptions("mergeServices")
@SupportedAnnotationTypes({
AspectImportPrism.PRISM_TYPE,
AssistFactoryPrism.PRISM_TYPE,
Expand Down Expand Up @@ -66,7 +66,7 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
APContext.init(processingEnv);
loadProvidedFiles();
ProcessingContext.init(moduleFileProvided);
ProcessingContext.registerProvidedTypes(moduleFileProvided);
moduleData.forEach(ProcessingContext::addModule);
this.elementUtils = processingEnv.getElementUtils();
this.allScopes = new AllScopes();
Expand Down Expand Up @@ -98,7 +98,6 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
*/
void loadProvidedFiles() {
pluginFileProvided.addAll(lines("avaje-plugin-provides.txt"));

lines("avaje-module-dependencies.csv").stream()
.filter(s -> s.contains("|") && !s.startsWith("External Module Type"))
.distinct()
Expand All @@ -110,6 +109,11 @@ void loadProvidedFiles() {
ExternalProvider.readMetaDataProvides(moduleFileProvided);
this.moduleData.add(m);
});
lines("avaje-plugins.csv").stream()
.filter(s -> s.contains("|") && !s.startsWith("External Plugin Type"))
.distinct()
.map(l -> l.split("\\|")[1])
.forEach(pluginFileProvided::add);
}

private List<String> lines(String relativeName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
final class ProcessingContext {

private static final String EVENTS_SPI = "io.avaje.inject.events.spi.ObserverManagerPlugin";
private static final ThreadLocal<Ctx> CTX = new ThreadLocal<>();
private static final ThreadLocal<Ctx> CTX = ThreadLocal.withInitial(Ctx::new);
private static boolean processingOver;
private ProcessingContext() {}

Expand All @@ -33,15 +33,15 @@ static final class Ctx {
private final List<TypeElement> delayQueue = new ArrayList<>();
private final Set<String> spiServices = new TreeSet<>();
private boolean strictWiring;
private final boolean mergeServices = APContext.getOption("mergeServices").map(Boolean::valueOf).orElse(true);

void registerProvidedTypes(Set<String> moduleFileProvided) {
ExternalProvider.registerModuleProvidedTypes(providedTypes);
providedTypes.addAll(moduleFileProvided);
}
}

static void init(Set<String> moduleFileProvided) {
CTX.set(new Ctx());
static void registerProvidedTypes(Set<String> moduleFileProvided) {
CTX.get().registerProvidedTypes(moduleFileProvided);
addEventSPI();
}
Expand Down Expand Up @@ -105,6 +105,12 @@ static void addInjectSPI(String type) {
CTX.get().spiServices.add(type);
}

static void addExternalInjectSPI(String type) {
if (CTX.get().mergeServices) {
CTX.get().spiServices.add(type);
}
}

static FileObject createMetaInfWriterFor(String interfaceType) throws IOException {
return filer().createResource(StandardLocation.CLASS_OUTPUT, "", interfaceType);
}
Expand Down Expand Up @@ -205,10 +211,6 @@ static void processingOver(boolean over) {
}

static void writeSPIServicesFile() {
Optional.ofNullable(APContext.getProjectModuleElement())
.filter(m -> "io.avaje.inject.test".equals(m.getQualifiedName().toString()))
.ifPresent(m -> CTX.get().spiServices.remove(EVENTS_SPI));

readExistingMetaInfServices();
if (CTX.get().spiServices.isEmpty()) {
// no services to register
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import io.avaje.inject.spi.InjectPlugin;
import io.avaje.inject.spi.InjectExtension;
import io.avaje.inject.spi.Module;
import io.avaje.inject.spi.Plugin;

import org.gradle.api.*;

import java.io.File;
Expand Down Expand Up @@ -47,7 +49,7 @@ private void writeProvides(Project project) {
}

try (var classLoader = classLoader(project);
var pluginWriter = createFileWriter(outputDir.getPath(), "avaje-plugin-provides.txt");
var pluginWriter = createFileWriter(outputDir.getPath(), "avaje-plugins.csv");
var moduleCSV = createFileWriter(outputDir.getPath(), "avaje-module-dependencies.csv")) {
writeProvidedPlugins(classLoader, pluginWriter);
writeModuleCSV(classLoader, moduleCSV);
Expand All @@ -61,29 +63,36 @@ private FileWriter createFileWriter(String dir, String file) throws IOException
}

private void writeProvidedPlugins(ClassLoader classLoader, FileWriter pluginWriter) throws IOException {
final Set<String> providedTypes = new HashSet<>();

List<InjectPlugin> allPlugins = new ArrayList<>();
ServiceLoader.load(io.avaje.inject.spi.Plugin.class, classLoader).forEach(allPlugins::add);
final List<InjectPlugin> plugins = new ArrayList<>();
ServiceLoader.load(Plugin.class, classLoader).forEach(plugins::add);
ServiceLoader.load(InjectExtension.class, classLoader).stream()
.map(Provider::get)
.filter(InjectPlugin.class::isInstance)
.map(InjectPlugin.class::cast)
.forEach(allPlugins::add);
.forEach(plugins::add);

final Map<String, List<String>> pluginEntries = new HashMap<>();
for (final var plugin : plugins) {

for (final var plugin : allPlugins) {
System.out.println("Loaded Plugin: " + plugin.getClass().getCanonicalName());
final List<String> provides = new ArrayList<>();
final var typeName = plugin.getClass().getTypeName();
System.out.println("Loaded Plugin: " + typeName);
for (final var provide : plugin.provides()) {
providedTypes.add(provide.getTypeName());
provides.add(provide.getTypeName());
}
for (final var provide : plugin.providesAspects()) {
providedTypes.add(wrapAspect(provide.getCanonicalName()));
provides.add(wrapAspect(provide.getCanonicalName()));
}
pluginEntries.put(typeName, provides);
}

for (final var providedType : providedTypes) {
pluginWriter.write(providedType);
pluginWriter.write("External Plugin Type|Provides");
for (final var providedType : pluginEntries.entrySet()) {
pluginWriter.write("\n");
pluginWriter.write(providedType.getKey());
pluginWriter.write("|");
var provides = providedType.getValue().stream().collect(joining(","));
pluginWriter.write(provides.isEmpty() ? " " : provides);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.avaje.inject.mojo;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

import java.io.File;
Expand All @@ -12,11 +11,11 @@
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
Expand Down Expand Up @@ -53,8 +52,6 @@ public class AutoProvidesMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;

private final List<ModuleData> modules = new ArrayList<>();

@Override
public void execute() throws MojoExecutionException {
final var listUrl = compileDependencies();
Expand All @@ -65,7 +62,7 @@ public void execute() throws MojoExecutionException {
}

try (var newClassLoader = createClassLoader(listUrl);
var pluginWriter = createFileWriter("avaje-plugin-provides.txt");
var pluginWriter = createFileWriter("avaje-plugins.csv");
var moduleCSV = createFileWriter("avaje-module-dependencies.csv")) {

writeProvidedPlugins(newClassLoader, pluginWriter);
Expand All @@ -79,9 +76,7 @@ public void execute() throws MojoExecutionException {
private List<URL> compileDependencies() throws MojoExecutionException {
final List<URL> listUrl = new ArrayList<>();
project.setArtifactFilter(new ScopeArtifactFilter("compile"));
final var deps = project.getArtifacts();

for (final Artifact artifact : deps) {
for (final Artifact artifact : project.getArtifacts()) {
try {
listUrl.add(artifact.getFile().toURI().toURL());
} catch (final MalformedURLException e) {
Expand All @@ -100,8 +95,6 @@ private FileWriter createFileWriter(String string) throws IOException {
}

private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter pluginWriter) throws IOException {
final Set<String> providedTypes = new HashSet<>();

final Log log = getLog();

final List<InjectPlugin> plugins = new ArrayList<>();
Expand All @@ -112,24 +105,31 @@ private void writeProvidedPlugins(URLClassLoader newClassLoader, FileWriter plug
.map(InjectPlugin.class::cast)
.forEach(plugins::add);

final Map<String, List<String>> pluginEntries = new HashMap<>();
for (final var plugin : plugins) {
log.info("Loaded Plugin: " + plugin.getClass().getTypeName());
final List<String> provides = new ArrayList<>();
final var typeName = plugin.getClass().getTypeName();
log.info("Loaded Plugin: " + typeName);
for (final var provide : plugin.provides()) {
providedTypes.add(provide.getTypeName());
provides.add(provide.getTypeName());
}
for (final var provide : plugin.providesAspects()) {
providedTypes.add(wrapAspect(provide.getCanonicalName()));
provides.add(wrapAspect(provide.getCanonicalName()));
}
pluginEntries.put(typeName, provides);
}

for (final var providedType : providedTypes) {
pluginWriter.write(providedType);
pluginWriter.write("External Plugin Type|Provides");
for (final var providedType : pluginEntries.entrySet()) {
pluginWriter.write("\n");
pluginWriter.write(providedType.getKey());
pluginWriter.write("|");
var provides = String.join(",", providedType.getValue());
pluginWriter.write(provides.isEmpty() ? " " : provides);
}
}

private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter) throws IOException {

final Log log = getLog();
final List<AvajeModule> avajeModules = new ArrayList<>();
ServiceLoader.load(Module.class, newClassLoader).forEach(avajeModules::add);
Expand All @@ -138,6 +138,8 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter)
.filter(AvajeModule.class::isInstance)
.map(AvajeModule.class::cast)
.forEach(avajeModules::add);

List<ModuleData> modules = new ArrayList<>();
for (final var module : avajeModules) {
final var name = module.getClass().getTypeName();
log.info("Detected External Module: " + name);
Expand Down Expand Up @@ -175,10 +177,10 @@ private void writeModuleCSV(ClassLoader newClassLoader, FileWriter moduleWriter)
moduleWriter.write("\n");
moduleWriter.write(avajeModule.name());
moduleWriter.write("|");
var provides = avajeModule.provides().stream().collect(joining(","));
var provides = String.join(",", avajeModule.provides());
moduleWriter.write(provides.isEmpty() ? " " : provides);
moduleWriter.write("|");
var requires = avajeModule.requires().stream().collect(joining(","));
var requires = String.join(",", avajeModule.requires());
moduleWriter.write(requires.isEmpty() ? " " : requires);
}
}
Expand Down
3 changes: 1 addition & 2 deletions inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ public BeanScope build() {
"Could not find any AvajeModule instances to wire. Possible Causes: \n"
+ "1. No beans have been defined.\n"
+ "2. The avaje-inject-generator depedency was not available during compilation\n"
+ "3. Perhaps using Gradle and a misconfigured IDE? Refer to https://avaje.io/inject#gradle"
+ "4. Perhaps this is a fat jar and you have not configured your maven asembly/shade or gradle build task to merge META-INF/services");
+ "3. Perhaps using Gradle and a misconfigured IDE? Refer to https://avaje.io/inject#gradle");
}

postConstructList.forEach(builder::addPostConstruct);
Expand Down