Bundle Annotations | bnd
Description: Manifest headers are challenging to keep in sync with the code in the bundle. It often takes several attempts to get all the details correct.

- # Bundle Annotations

  Manifest headers are challenging to keep in sync with the code in the bundle. It often takes several attempts to get all the details correct.

  One of the goals of bnd is to eliminate such issues by relying on Java’s type system to express the semantics of OSGi metadata.

  To address this bnd pioneered manifest annotations which evolved into OSGi’s bundle annotations. A bundle annotation is used to express metadata that cannot otherwise be derived from code.

  A bundle annotation is applied to a type or package and when processed by bnd will cause the generation of corresponding manifest headers (and header clauses). Generating manifest headers from type safe structures is far less likely to result in errors, simplifies the developers life and is more conducive to code refactoring which won’t result in information loss.

  The following example shows the preferred way to handle package versioning by applying the `@Export` and `@Version` bundle annotations to `com/acme/package-info.java`.

      @Export
      @Version("1.3.4")
      package com.acme;

  which results in the manifest header:

      Export-Package: com.acme;version="1.3.4"

  ### @Requirement & @Capability Annotations

  Though Java class files contain enough information to find code dependencies, there are many dependencies that are indirect. OSGi extenders for instance are often a requirement to make a bundle function correctly but often client bundles have no code dependency on the extender. For example, Declarative Services (DS) went out of its way to allow components to be Plain Old Java Objects (POJO). The result is that resolving a closure of bundles starting from a DS client bundle would not drag in the Service Component Runtime (SCR), resulting in a satisfied but rather idle closure.

  The solution was to describe the requirement for the runtime SCR dependency using Requirements and Capabilities. But again, writing these complex clauses in the manifest by hand is both error prone and painful.

  The `@Requirement` and `@Capability` annotations were designed to address this issue. These annotations can be used to create custom bundle annotations, described later on. Let’s discuss the DS example.

  Recent DS specifications require implementations to provide the following capability:

      Provide-Capability: osgi.extender;
          osgi.extender="osgi.component";
          version:Version="1.4.0";
          uses:="org.osgi.service.component"

  While this provides a capability that can be required, we need a requirement to be generated from client code that uses DS. Enter recent versions of DS annotations which are meta-annotated with `@RequireServiceComponentRuntime`, a custom bundle annotation which is specified as:

      @Requirement(
          namespace = ExtenderNamespace.EXTENDER_NAMESPACE,
      	name = ComponentConstants.COMPONENT_CAPABILITY_NAME,
      	version = ComponentConstants.COMPONENT_SPECIFICATION_VERSION)
      @Retention(RetentionPolicy.CLASS)
      public @interface RequireServiceComponentRuntime { }

  If you inspect the source code for `@Component` you’ll find it is meta-annotated with `@RequireServiceComponentRuntime`. When you write a DS component using `@Component` as follows

      @Component
      class Foo { ... }

  and because of the inherent bundle annotations it holds, the following manifest clause is generated

      Require-Capability: \
      	osgi.extender; \
      	filter:="(&(osgi.extender=osgi.component)(version>=1.4.0)(!(version>=2.0.0)))"

  The invisible link created between user code and the indirect requirement is a powerful mechanism that enables automatic validation of a bundle closure.

  The actual requirement `filter:` directive is constructed from an `AND` of the `filter()`, `name()`, and `version()` annotation methods. All fields are optional. The name field will create an assertion that the given namespace equals the value of the `name()` annotation method. For example, if the namespace is `com.example.foo` and the `name()` method has the value `bar` then the filter is `(com.example.foo=bar)`. If a version is specified, it will be expanded to a filtered version-range expression. The convention of using the namespace name as the property key is commonly used in OSGi specification. For example, the filter `(osgi.wiring.package=com.example.foo)` is the filter for an Import-Package `com.example.foo` while `osgi.wiring.package` is the namespace for the packages.

  For example:

      @Requirement(namespace = "NAMESPACE", name="NAME", version="1.2.3", filter="(foo=${#foo})")
      @Retention(RetentionPolicy.CLASS)
      public @interface RequireSomething {
          int foo();
      }

      @RequireSomething(foo=3)
      class Foo {...}

  This will generate a manifest Require-Capability header of:

      Require-Capability: \
          NAMESPACE; \
          filter:="(&(foo=3)(NAMESPACE=NAME)(version>=1.2.3)(!(version>=2.0.0)))"

  ### Arbitrary Manifest Headers

  Bundle annotations aren’t just about package versioning or requirements and capabilities. They are about lifting metadata out of our code to avoid, among other things, error prone duplication of information. A common example is the bundle activator. Bundle Activators are require to be described in a manifest header. This association is not visible to refactoring tools and as such can easily end up out of sync.

  The `@Header` annotation exists to address this problem.

      package com.acme;

      @Header(name = Constants.BUNDLE_ACTIVATOR, value = "${@class}")
      public Activator implements BundleActivator { ... }

  results in the manifest header:

  `Bundle-Activator: com.acme.Activator`

  ### Macros

  You’ll note the string `${@class}` used in the above example. String fields in bundle annotations are processed through bnd’s macro processor. This macro processor provides access to all default and builder macros. More info on bnd macros can be found in the macros chapter.

  Bnd also provides access to certain key properties of the current processing state.

  - @class - gives the fully qualified name of the annotated class
  - @class-short - gives the simple name of the annotated class
  - @package - gives the package of the annotated class
  - @version - gives the package version of the annotated class

  The `@Header` example above used the macro `${@class}` which lifted the `@class` property holding the class name of the activator into the header to avoid having to duplicate it. This also means that refactoring the activator won’t cause the manifest to get out of sync.

  In the case that a bundle annotation is used as a meta annotation then the methods on the annotated annotation are available as macros as well with a name prefixed with `#`. That is, if the annotated annotation has a method `foo()`, then the macro `${#foo}` can be used to refer to its value. See Accessor Properties for more details.

  ### Custom Bundle Annotations

  Certain bundle annotations have a second important use. We know that if applied to a type or package bundle annotations result in a clause in the manifest. However, many can be used as meta-annotations to a second annotation. The second annotation is considered a custom bundle annotation. The custom bundle annotation results in a manifest clause only when applied to a type or package.

  This makes it possible to create an annotation for a subsystem. For example, an annotation `@ASL_2_0` that sets the `Bundle-License` header to the Apache Software License version 2.0.

      @BundleLicense(
          name = "https://www.opensource.org/licenses/apache2.0.php",
          link = "https://www.apache.org/licenses/LICENSE-2.0.html",
          description = "Apache Software License 2.0")
      @interface ASL_2_0 {}

      // takes effect when applied to a type

      @ASL_2_0
      class Foo { ... }

  #### Adding Attributes and Directives

  When creating custom bundle annotations a common requirement is to make them parameterizable such that the values of the custom bundle annotation feed into the header clauses resulting from the bundle annotation applied to it (remember; a custom bundle annotation is meta-annotated with a bundle annotation.)

  OSGi specifies two annotations, `@Attribute` and `@Directive`, for this purpose. Any methods of the custom bundle annotation annotated with `@Attribute` or `@Directive` will result in those becoming additional attributes or directives respectively of the resulting header clause when a value is supplied.

  ##### `@Attribute`

  `@Attribute` allows you to add new or update existing attributes from the bundle annotation.

      @Capability(namespace = "foo.namespace")
      @interface Extended {
      	@Attribute("foo.attribute") // this attribute enhances the @Capability
      	String value();
      }

      // usage

      @Extended("bar")
      class Foo {}

  which results in the manifest header:

  `Provide-Capability: foo.namespace;foo.attribute=bar`

  ##### `@Directive`

  `@Directive` behaves similarly; with some caveats. You can add new or update existing directives for namespaces not defined by OSGi specifications.

      @Capability(namespace = "foo.namespace")
      @interface Extended {
      	@Directive("foo.directive")
      	String value();
      }

      // usage

      @Extended("bar")
      class Foo {}

  results in the manifest header:

  `Provide-Capability: foo.namespace;foo.directive:=bar`

  However, namespaces defined by OSGi specifications will be validated and will not accept directives which are not part of the spec unless they are prefixed with `x-`.

      @Capability(namespace = "osgi.extender", name = "bar", version = "1.0.0")
      @interface Extended {
      	@Directive("foo")
      	String value();
      }

      // usage

      @Extended("bar")
      public class Foo {}

  will result in an error:

  `Unknown directive 'foo:' for namespace 'osgi.extender' in 'Provide-Capability'. Allowed directives are [effective:,uses:], and 'x-*'.`

  It should be noted that it’s possible to elide such errors using bnd’s `-fixupmessages` instruction.

  This next example however:

      @Capability(namespace = "osgi.extender", name = "bar", version = "1.0.0")
      @interface Extended {
      	@Directive("x-foo")
      	String value();
      }

      // usage

      @Extended("bar")
      public class Foo {}

  results in the manifest header:

  `Provide-Capability: osgi.extender;osgi.extender=bar;version:Version="1.0.0";x-foo:=bar`

  It should be noted that default values for methods annotated with `@Attribute` and `@Directive` are deemed to be for documentation purposes only and will not be emitted into resulting headers.

  #### Accessor Properties

  For more customisation options see chapter on Accessor Properties.

  ### Where to find Bundle Annotations

  OSGi bundle annotations can be found in the `osgi.annotation` (e.g. `org.osgi:osgi.annotation:7.0.0`) bundle.

      <dependency>
        <groupId>org.osgi</groupId>
        <artifactId>osgi.annotation</artifactId>
        <version>7.0.0</version>
      </dependency>

  Bnd bundle annotations can be found in the `biz.aQute.bnd.annotations` (e.g. `biz.aQute.bnd:biz.aQute.bnd.annotation:5.0.0`) bundle.

      <dependency>
        <groupId>biz.aQute.bnd</groupId>
        <artifactId>biz.aQute.bnd.annotation</artifactId>
        <version>${bnd.version}</version>
      </dependency>

  ### List of Bundle Annotations

  OSGi Bundle Annotations:

  - `@Attribute`
  - `@Capability`
  - `@Directive`
  - `@Export`
  - `@Header`
  - `@Requirement`
  - Many OSGi Specifications also define their own custom bundle annotations
    - `@RequireConfigurationAdmin`
    - `@RequireMetaTypeExtender`
    - `@RequireMetaTypeImplementation`
    - `@RequireServiceComponentRuntime`
    - `@RequireEventAdmin`
    - `@RequireJPAExtender`
    - `@RequireHttpWhiteboard`
    - `@RequireConfigurator`
    - `@RequireJaxrsWhiteboard`
    - `@JSONRequired`
    - `@RequireCDIExtender`
    - `@RequireCDIImplementation`

  Bnd Bundle Annotations:

  - `@BundleCategory` – Sets the bundle category, existing categories are defined in an enum.
  - `@BundleContributors` – Creates an OSGi header for contributors that maps to the Maven contributors element.
  - `@BundleCopyright` – Sets the copyright header.
  - `@BundleDevelopers` – Creates an OSGi header for developers that maps to the Maven developers element.
  - `@BundleDocUrl` – Provides a documentation URL.
  - `@BundleLicense` - Creates entries in the `Bundle-License` header.
    - `@ASL_2_0`
    - `@BSD_2_Clause`
    - `@BSD_3_Clause`
    - `@CDDL_1_0`
    - `@CPL_1_0`
    - `@EPL_1_0`
    - `@GPL_2_0`
    - `@GPL_3_0`
    - `@LGPL_2_1`
    - `@MIT_1_0`
    - `@MPL_2_0`
  - `@ServiceConsumer` - Generates requirements in support of the consumer side of the Service Loader Mediator specification.
  - `@ServiceProvider` - Generates requirements and capabilities in support of the provider side of the Service Loader Mediator specification. Also generates `META-INF/service` descriptors.