From 51e98ddf1f197a3e1629294cee97f0dba87383ba Mon Sep 17 00:00:00 2001 From: Paul Latzelsperger <43503240+paullatzelsperger@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:09:33 +0100 Subject: [PATCH] feat: autodoc parse @Configuration objects (#289) --- .../core/processor/EdcModuleProcessor.java | 2 +- .../introspection/ExtensionIntrospector.java | 19 +++++++++++---- .../introspection/ModuleIntrospector.java | 23 +++++++++++++++++-- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/EdcModuleProcessor.java b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/EdcModuleProcessor.java index 0a4542f0..7a5e29dc 100644 --- a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/EdcModuleProcessor.java +++ b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/EdcModuleProcessor.java @@ -89,7 +89,7 @@ public synchronized void init(ProcessingEnvironment processingEnv) { //todo: replace this Noop converter with an actual JavadocConverter overviewIntrospector = new OverviewIntrospector(javadoc -> javadoc, processingEnv.getElementUtils()); - extensionIntrospector = new ExtensionIntrospector(processingEnv.getElementUtils()); + extensionIntrospector = new ExtensionIntrospector(processingEnv.getElementUtils(), processingEnv.getTypeUtils()); } @Override diff --git a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ExtensionIntrospector.java b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ExtensionIntrospector.java index bb8222b4..3500c7ec 100644 --- a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ExtensionIntrospector.java +++ b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ExtensionIntrospector.java @@ -15,6 +15,7 @@ package org.eclipse.edc.plugins.autodoc.core.processor.introspection; import org.eclipse.edc.plugins.autodoc.core.processor.compiler.AnnotationFunctions; +import org.eclipse.edc.runtime.metamodel.annotation.Configuration; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; @@ -36,6 +37,7 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toList; @@ -51,9 +53,11 @@ public class ExtensionIntrospector { public static final String CONTEXT_ATTRIBUTE = "context"; private final Elements elementUtils; + private final Types typeUtils; - public ExtensionIntrospector(Elements elementUtils) { + public ExtensionIntrospector(Elements elementUtils, Types typeUtils) { this.elementUtils = elementUtils; + this.typeUtils = typeUtils; } /** @@ -102,7 +106,10 @@ public List resolveProvidedServices(Element element) { * Resolves configuration points declared with {@link Setting}. */ public List resolveConfigurationSettings(Element element) { - return getEnclosedElementsAnnotatedWith(element, Setting.class) + var settingsInConfigObjects = getEnclosedElementsAnnotatedWith(element, Configuration.class) + .flatMap(e -> getEnclosedElementsAnnotatedWith(typeUtils.asElement(e.asType()), Setting.class)); + + return Stream.concat(settingsInConfigObjects, getEnclosedElementsAnnotatedWith(element, Setting.class)) .filter(VariableElement.class::isInstance) .map(VariableElement.class::cast) .map(this::createConfigurationSetting) @@ -139,9 +146,13 @@ private ConfigurationSetting createConfigurationSetting(VariableElement settingE prefix = resolveConfigurationPrefix(settingElement); } - var keyValue = prefix + settingElement.getConstantValue().toString(); + // either take the config key value directly from the annotated variable or from the "key" attribute + var keyValue = prefix + ofNullable(settingElement.getConstantValue()) + .orElseGet(() -> attributeValue(String.class, "key", settingMirror, elementUtils)) + .toString(); - return ConfigurationSetting.Builder.newInstance().key(keyValue) + return ConfigurationSetting.Builder.newInstance() + .key(keyValue) .description(attributeValue(String.class, "value", settingMirror, elementUtils)) .type(attributeValue(String.class, "type", settingMirror, elementUtils)) .required(attributeValue(Boolean.class, "required", settingMirror, elementUtils)) diff --git a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ModuleIntrospector.java b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ModuleIntrospector.java index 9a186f5f..06c8830d 100644 --- a/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ModuleIntrospector.java +++ b/plugins/autodoc/autodoc-processor/src/main/java/org/eclipse/edc/plugins/autodoc/core/processor/introspection/ModuleIntrospector.java @@ -14,6 +14,7 @@ package org.eclipse.edc.plugins.autodoc.core.processor.introspection; +import org.eclipse.edc.runtime.metamodel.annotation.Configuration; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; import org.eclipse.edc.runtime.metamodel.annotation.Inject; @@ -21,6 +22,7 @@ import org.eclipse.edc.runtime.metamodel.annotation.Provides; import org.eclipse.edc.runtime.metamodel.annotation.Requires; import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.runtime.metamodel.annotation.Settings; import org.eclipse.edc.runtime.metamodel.annotation.Spi; import org.eclipse.edc.runtime.metamodel.domain.Service; @@ -93,13 +95,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 getExtensionElements(RoundEnvironment environment) { + + var settingsSymbols = environment.getElementsAnnotatedWith(Setting.class).stream() .peek(setting -> { + var serviceExtensionType = typeUtils.erasure(elementUtils.getTypeElement(SYSTEM_EXTENSION_NAME).asType()); var enclosingElement = setting.getEnclosingElement().asType(); + + // @Setting annotations may only occur in extension classes or in types annotated with @Settings + if (!typeUtils.isAssignable(enclosingElement, serviceExtensionType) && setting.getEnclosingElement().getAnnotation(Settings.class) == null) { + var message = "@Setting annotation must be used inside a ServiceExtension implementation or a type annotated with @Settings, the " + + "ones defined in %s will be excluded from the autodoc manifest".formatted(enclosingElement); + processingEnv.getMessager().printMessage(ERROR, message, setting); + } + }); + + // check that fields annotated with @Configuration occur only inside extension classes + environment.getElementsAnnotatedWith(Configuration.class) + .forEach(setting -> { var serviceExtensionType = typeUtils.erasure(elementUtils.getTypeElement(SYSTEM_EXTENSION_NAME).asType()); + var enclosingElement = setting.getEnclosingElement().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); + var message = "@Configuration annotations 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); } });