Skip to content

Commit

Permalink
bundle annotations: Support replacement of enum types
Browse files Browse the repository at this point in the history
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 quarkusio/quarkus#19970 and
eclipse/microprofile-config#716.

We support the use of enum values or string values as the annotation
element value through existing conversion support. The OSGi change in
osgi/osgi#404 will move from using enum types
to use string values which are case-insensitive equivalent to the
enum value names.

We seamlessly handle old and new annotations using the old enum values
or the new string values. Prior to this fix, Bnd already handled the
change through a fallback in Converter which uppercased the string value
before converting to an internal enum value. This change avoids the
internal enum type and processes the string value or string name of the
enum value when processing older versions of the OSGi annotations.

Signed-off-by: BJ Hargrave <[email protected]>
  • Loading branch information
bjhargrave committed Feb 7, 2022
1 parent 70df4e1 commit 56d1103
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -14,5 +14,5 @@ public class ResolutionDirectiveOverride {}
String name();

@Directive
Resolution resolution() default Resolution.MANDATORY;
String resolution() default Namespace.RESOLUTION_MANDATORY;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -14,5 +14,5 @@ public class CardinalityDirectiveOverride {}
String name();

@Directive
Cardinality cardinality() default Cardinality.SINGLE;
String cardinality() default Namespace.CARDINALITY_SINGLE;
}
4 changes: 3 additions & 1 deletion biz.aQute.bndlib/src/aQute/bnd/osgi/Analyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
59 changes: 49 additions & 10 deletions biz.aQute.bndlib/src/aQute/bnd/osgi/AnnotationHeaders.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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());
}

Expand Down

0 comments on commit 56d1103

Please sign in to comment.