Skip to content

Commit

Permalink
feat: autodoc error on misplaced @setting annotations (#228)
Browse files Browse the repository at this point in the history
* feat: print warning on misplaced @setting annotations

* fail when @setting is defined in a non-extension class
  • Loading branch information
ndr-brt authored Mar 19, 2024
1 parent 5138526 commit 46a48d0
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 357 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.StandardLocation;

Expand All @@ -52,8 +53,8 @@
* {@link #EDC_OUTPUTDIR_OVERRIDE} as a processor parameter.
*/
@SupportedAnnotationTypes({
"org.eclipse.edc.runtime.metamodel.annotation.EdcSetting",
"org.eclipse.edc.runtime.metamodel.annotation.EdcSettingContext",
"org.eclipse.edc.runtime.metamodel.annotation.Setting",
"org.eclipse.edc.runtime.metamodel.annotation.SettingContext",
"org.eclipse.edc.runtime.metamodel.annotation.Extension",
"org.eclipse.edc.runtime.metamodel.annotation.Spi",
"org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint",
Expand All @@ -72,19 +73,19 @@ public class EdcModuleProcessor extends AbstractProcessor {
private final ObjectMapper mapper = new ObjectMapper();

private ModuleIntrospector moduleIntrospector;

private OverviewIntrospector overviewIntrospector;

private EdcModule.Builder moduleBuilder;
private EdcServiceExtension.Builder extensionBuilder;
private ExtensionIntrospector extensionIntrospector;

private ModuleType moduleType;
private Set<Element> extensionElements;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
moduleIntrospector = new ModuleIntrospector(processingEnv.getElementUtils(), processingEnv.getTypeUtils());
moduleIntrospector = new ModuleIntrospector(processingEnv);
//todo: replace this Noop converter with an actual JavadocConverter
overviewIntrospector = new OverviewIntrospector(javadoc -> javadoc, processingEnv.getElementUtils());

Expand All @@ -93,8 +94,11 @@ public synchronized void init(ProcessingEnvironment processingEnv) {

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment environment) {
if (!initializeModuleBuilder(environment)) {
return false; // error, do not continue processing
if (moduleBuilder == null) {
var result = initializeModuleBuilder(environment);
if (!result) {
return false; // error, do not continue processing
}
}

if (environment.processingOver()) {
Expand All @@ -105,8 +109,6 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
}

if (moduleType == ModuleType.EXTENSION) {
var extensionElements = moduleIntrospector.getExtensionElements(environment);

extensionElements.forEach(element -> {
extensionBuilder = EdcServiceExtension.Builder.newInstance().type(moduleType)
.name(extensionIntrospector.getExtensionName(element))
Expand All @@ -116,6 +118,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
.configuration(extensionIntrospector.resolveConfigurationSettings(element))
.overview(overviewIntrospector.generateModuleOverview(moduleType, environment))
.categories(extensionIntrospector.getExtensionCategories(element));

moduleBuilder.extension(extensionBuilder.build());
});
} else {
Expand All @@ -129,11 +132,6 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
}

private boolean initializeModuleBuilder(RoundEnvironment environment) {
if (moduleBuilder != null) {
// already initialized in a previous round
return true;
}

var id = processingEnv.getOptions().get(ID);
if (id == null) {
processingEnv.getMessager().printMessage(ERROR, "Value for '" + ID + "' not set on processor configuration. Skipping manifest generation.");
Expand All @@ -146,7 +144,8 @@ private boolean initializeModuleBuilder(RoundEnvironment environment) {
return false;
}

moduleType = determineAndValidateModuleType(environment);
extensionElements = moduleIntrospector.getExtensionElements(environment);
moduleType = determineAndValidateModuleType(environment, extensionElements);
if (moduleType == ModuleType.INVALID) {
// error or not a module, return
return false;
Expand All @@ -158,8 +157,7 @@ private boolean initializeModuleBuilder(RoundEnvironment environment) {
}

@Nullable
private ModuleType determineAndValidateModuleType(RoundEnvironment environment) {
var extensionElements = moduleIntrospector.getExtensionElements(environment);
private ModuleType determineAndValidateModuleType(RoundEnvironment environment, Set<Element> extensionElements) {
if (extensionElements.isEmpty()) {
// check if it is an SPI
var spiElements = environment.getElementsAnnotatedWith(Spi.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import static java.util.stream.Collectors.toList;
import static javax.tools.Diagnostic.Kind.ERROR;
import static org.eclipse.edc.plugins.autodoc.core.processor.compiler.AnnotationFunctions.attributeStringValues;
import static org.eclipse.edc.plugins.autodoc.core.processor.compiler.AnnotationFunctions.attributeValue;
import static org.eclipse.edc.plugins.autodoc.core.processor.compiler.AnnotationFunctions.mirrorFor;
Expand All @@ -46,10 +48,12 @@ public class ModuleIntrospector {
private static final String SERVICE_EXTENSION_NAME = "org.eclipse.edc.spi.system.ServiceExtension";
private final Elements elementUtils;
private final Types typeUtils;
private final ProcessingEnvironment processingEnv;

public ModuleIntrospector(Elements elementUtils, Types typeUtils) {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
public ModuleIntrospector(ProcessingEnvironment processingEnv) {
this.processingEnv = processingEnv;
this.elementUtils = processingEnv.getElementUtils();
this.typeUtils = processingEnv.getTypeUtils();
}


Expand Down Expand Up @@ -89,23 +93,30 @@ public String getModuleName(RoundEnvironment environment) {
* @return a set containing the distinct extension symbols. Elements in that set are most likely of type Symbol.ClassSymbol
*/
public Set<Element> getExtensionElements(RoundEnvironment environment) {
var extensionClasses = environment.getElementsAnnotatedWith(Extension.class);
var settingsSymbols = environment.getElementsAnnotatedWith(Setting.class);
var settingsSymbols = environment.getElementsAnnotatedWith(Setting.class).stream()
.peek(setting -> {
var enclosingElement = setting.getEnclosingElement().asType();
var serviceExtensionType = typeUtils.erasure(elementUtils.getTypeElement(SERVICE_EXTENSION_NAME).asType());
if (!typeUtils.isAssignable(enclosingElement, serviceExtensionType)) {
var message = "@Setting annotation must be used inside a ServiceExtension implementation, the " +
"ones defined in %s will be excluded from the autodoc manifest".formatted(enclosingElement);
processingEnv.getMessager().printMessage(ERROR, message, setting);
}
});

var injectSymbols = environment.getElementsAnnotatedWith(Inject.class);
var providerSymbols = environment.getElementsAnnotatedWith(Provider.class);
var providesClasses = environment.getElementsAnnotatedWith(Provides.class);
var requiresClasses = environment.getElementsAnnotatedWith(Requires.class);

var symbols = settingsSymbols.stream();
symbols = Stream.concat(symbols, injectSymbols.stream());
symbols = Stream.concat(symbols, providerSymbols.stream());

var classes = symbols.map(Element::getEnclosingElement)
var classes = Stream.of(settingsSymbols, injectSymbols.stream(), providerSymbols.stream())
.reduce(Stream::concat)
.orElse(Stream.empty())
.map(Element::getEnclosingElement)
.filter(this::isExtension)
.collect(Collectors.toSet());
classes.addAll(requiresClasses);
classes.addAll(providesClasses);
classes.addAll(extensionClasses);

classes.addAll(environment.getElementsAnnotatedWith(Requires.class));
classes.addAll(environment.getElementsAnnotatedWith(Provides.class));
classes.addAll(environment.getElementsAnnotatedWith(Extension.class));

return classes;
}
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 46a48d0

Please sign in to comment.