From e9fdaf1450cf8b741d04a3566c6efacf5b85f2a9 Mon Sep 17 00:00:00 2001 From: BJ Hargrave Date: Mon, 7 Feb 2022 14:35:19 -0500 Subject: [PATCH] bundle annotations: Replace use of enum types Using enum types in the CLASS retention bundle annotations is causing issues for those using the annotations. Various tools, such as javadoc, attempt to reify the elements in the annotations and since the osgi.annotation jar is generally a scope=provided dependency, the enum types are not available to downstream users of the jars using the OSGi annotations and so tools generates an annoying warning. See https://github.com/quarkusio/quarkus/issues/19970 and https://github.com/eclipse/microprofile-config/issues/716. To address this, we support the use of enum values or string values as the annotation element value. This will support the OSGi change in https://github.com/osgi/osgi/pull/404 We seamlessly handle old and new annotations using the old enum values or the new string values. So moving to using the updated OSGi annotations will also require moving to use Bnd with this fix. Signed-off-by: BJ Hargrave --- .../std/a/ResolutionDirectiveOverride.java | 6 +- .../std/b/CardinalityDirectiveOverride.java | 6 +- .../src/aQute/bnd/osgi/Analyzer.java | 4 +- .../src/aQute/bnd/osgi/AnnotationHeaders.java | 59 +++++++++++++++---- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/a/ResolutionDirectiveOverride.java b/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/a/ResolutionDirectiveOverride.java index 657fc014c17..e46145a9b7c 100644 --- a/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/a/ResolutionDirectiveOverride.java +++ b/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/a/ResolutionDirectiveOverride.java @@ -3,9 +3,9 @@ import org.osgi.annotation.bundle.Attribute; import org.osgi.annotation.bundle.Directive; import org.osgi.annotation.bundle.Requirement; -import org.osgi.annotation.bundle.Requirement.Resolution; +import org.osgi.resource.Namespace; -@Custom(name = "bar", resolution = Resolution.OPTIONAL) +@Custom(name = "bar", resolution = Namespace.RESOLUTION_OPTIONAL) public class ResolutionDirectiveOverride {} @Requirement(namespace = "foo") @@ -14,5 +14,5 @@ public class ResolutionDirectiveOverride {} String name(); @Directive - Resolution resolution() default Resolution.MANDATORY; + String resolution() default Namespace.RESOLUTION_MANDATORY; } diff --git a/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/b/CardinalityDirectiveOverride.java b/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/b/CardinalityDirectiveOverride.java index d48b208518d..53d93c86b90 100644 --- a/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/b/CardinalityDirectiveOverride.java +++ b/biz.aQute.bndlib.tests/test/test/annotationheaders/attrs/std/b/CardinalityDirectiveOverride.java @@ -3,9 +3,9 @@ import org.osgi.annotation.bundle.Attribute; import org.osgi.annotation.bundle.Directive; import org.osgi.annotation.bundle.Requirement; -import org.osgi.annotation.bundle.Requirement.Cardinality; +import org.osgi.resource.Namespace; -@Custom(name = "bar", cardinality = Cardinality.MULTIPLE) +@Custom(name = "bar", cardinality = Namespace.CARDINALITY_MULTIPLE) public class CardinalityDirectiveOverride {} @Requirement(namespace = "foo") @@ -14,5 +14,5 @@ public class CardinalityDirectiveOverride {} String name(); @Directive - Cardinality cardinality() default Cardinality.SINGLE; + String cardinality() default Namespace.CARDINALITY_SINGLE; } diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java index 9d9ac8efc05..52b4495ccbf 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java @@ -27,6 +27,7 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -841,7 +842,8 @@ public void annotation(Annotation a) { Object substitution = a.get("substitution"); if (substitution != null) { - switch (substitution.toString()) { + switch (substitution.toString() + .toUpperCase(Locale.ROOT)) { case "CONSUMER" : info.put(PROVIDE_DIRECTIVE, "false"); break; diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/AnnotationHeaders.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/AnnotationHeaders.java index 368eb37150d..473210a68d1 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/AnnotationHeaders.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/AnnotationHeaders.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; @@ -18,6 +19,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.osgi.resource.Namespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +36,7 @@ import aQute.bnd.bundle.annotations.Headers; import aQute.bnd.bundle.annotations.Requirement; import aQute.bnd.bundle.annotations.Requirements; +import aQute.bnd.exceptions.Exceptions; import aQute.bnd.header.Attrs; import aQute.bnd.header.OSGiHeader; import aQute.bnd.header.Parameters; @@ -42,13 +45,12 @@ import aQute.bnd.osgi.Descriptors.PackageRef; import aQute.bnd.osgi.Descriptors.TypeRef; import aQute.bnd.stream.MapStream; +import aQute.bnd.unmodifiable.Sets; import aQute.bnd.version.Version; import aQute.bnd.version.VersionRange; import aQute.lib.collections.MultiMap; import aQute.lib.converter.Converter; -import aQute.bnd.exceptions.Exceptions; import aQute.lib.strings.Strings; -import aQute.bnd.unmodifiable.Sets; /** * This class parses the 'header annotations'. Header annotations are @@ -740,23 +742,60 @@ private void doRequirement(Annotation a, Requirement annotation) throws Exceptio "The Requirement annotation with namespace %s applied to class %s has invalid filter information.", annotation.namespace(), current.getFQN()); } - req.append(";filter:='") + req.append(';') + .append(Namespace.REQUIREMENT_FILTER_DIRECTIVE) + .append(':') + .append('=') + .append('\'') .append(filter) .append('\''); } - if (a.containsKey("resolution")) { - req.append(";resolution:=") - .append(annotation.resolution()); + Object resolution = a.get("resolution"); + if (resolution != null) { + String value = resolution.toString() + .toLowerCase(Locale.ROOT); + switch (value) { + case Namespace.RESOLUTION_MANDATORY : + case Namespace.RESOLUTION_OPTIONAL : + req.append(';') + .append(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE) + .append(':') + .append('=') + .append(value); + break; + default : + analyzer.error("Requirement annotation in %s has invalid resolution value: %s", current, + resolution); + break; + } } - if (a.containsKey("cardinality")) { - req.append(";cardinality:=") - .append(annotation.cardinality()); + Object cardinality = a.get("cardinality"); + if (cardinality != null) { + String value = cardinality.toString() + .toLowerCase(Locale.ROOT); + switch (value) { + case Namespace.CARDINALITY_SINGLE : + case Namespace.CARDINALITY_MULTIPLE : + req.append(';') + .append(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE) + .append(':') + .append('=') + .append(value); + break; + default : + analyzer.error("Requirement annotation in %s has invalid cardinality value: %s", current, + cardinality); + break; + } } if (a.containsKey("effective")) { - req.append(";effective:="); + req.append(';') + .append(Namespace.REQUIREMENT_EFFECTIVE_DIRECTIVE) + .append(':') + .append('='); escape(req, annotation.effective()); }