@Component Annotation
An component is a piece of code that is managed by OSGi container. The container would be responsible for its instantiation and management.
Attributes of a component:

The above table have been noted from: https://www.knopflerfish.org/releases/5.2.0/docs/javadoc/org/osgi/service/component/annotations/Component.html
- configurationPolicy: The attribute can hold following values of ConfigurationPolicy
- IGNORE: Always allow the component configuration to be satisfied and do not use the corresponding Configuration object even if it is present.
- OPTIONAL: Use the corresponding Configuration object if present but allow the component to be satisfied even if the corresponding Configuration object is not present.
- REQUIRE: There must be a corresponding Configuration object for the component configuration to become satisfied. A component is activated only after all its service dependencies are satisfied by the container.
- factory: used to create a configuration factory. More implementation details are available on link.
- name: The attribute doesn’t support special characters. If invalid, the component will not be registered.
- property: A replacement for “@Properties felix annotation used at Class-level”.
- service: registers component as a Service. More implementation details available on link.
Example:
To create a component, add @Component annotation to a class. Also, configure its attributes as per your need.
In the following example, we have:
- @Activate annotation: It is used to mark a function which would be called when the component activates. The function can have any name.
- @Deactivate annotation: It is used to mark a function which would be called when the component deactivates. The function can have any name.
- Declared a custom property using property attribute.
| package blog.techrevel.component.impl; | |
| import org.osgi.service.component.annotations.Component; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import org.osgi.service.component.ComponentContext; | |
| import org.osgi.service.component.annotations.Activate; | |
| import org.osgi.service.component.annotations.Deactivate; | |
| @Component(name = "Sample Component", property = { "testProperty=Hello" }) | |
| public class SampleComponentImpl { | |
| private static final Logger LOGGER = LoggerFactory.getLogger(SampleComponentImpl.class); | |
| @Activate | |
| protected void activate(ComponentContext componentContext) { | |
| LOGGER.info("Registering: " + componentContext.getProperties().get("testProperty").toString()); | |
| } | |
| @Deactivate | |
| protected void deactivate(ComponentContext componentContext) { | |
| LOGGER.info("Deregistering: " + componentContext.getProperties().get("testProperty").toString()); | |
| } | |
| } |
More on defining property:
The property annotations have moved to their own class which declutters the component or service. For components with a large amount of properties, create an independent class, while a component with only one or two properties may be fine as a subclass.
A property value is read from componentContext in @Activate/@Deactivate methods.
If you need multiple properties for a component, declare them as an indiviadual value array of values for property attribute:
| package blog.techrevel.component.impl; | |
| import org.osgi.service.component.annotations.Component; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import org.osgi.service.component.ComponentContext; | |
| import org.osgi.service.component.annotations.Activate; | |
| import org.osgi.service.component.annotations.Deactivate; | |
| @Component(property = { "testProperty1=Hello", "testProperty2=World" }) | |
| public class MultipleComponentPropertiesImpl { | |
| private static final Logger LOGGER = LoggerFactory.getLogger(MultipleComponentPropertiesImpl.class); | |
| @Activate | |
| protected void activate(ComponentContext componentContext) { | |
| LOGGER.info("Registering: " + componentContext.getProperties().get("testProperty1").toString()); | |
| LOGGER.info("Registering: " + componentContext.getProperties().get("testProperty2").toString()); | |
| } | |
| @Deactivate | |
| protected void deactivate(ComponentContext componentContext) { | |
| LOGGER.info("Deregistering: " + componentContext.getProperties().get("testProperty1").toString()); | |
| LOGGER.info("DeRegistering: " + componentContext.getProperties().get("testProperty2").toString()); | |
| } | |
| } |
To define multiple values of a property, create each value as a separate element of the property Array.
| package blog.techrevel.component.impl; | |
| import org.osgi.service.component.annotations.Component; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import java.lang.reflect.Array; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import org.osgi.service.component.ComponentContext; | |
| import org.osgi.service.component.annotations.Activate; | |
| import org.osgi.service.component.annotations.Deactivate; | |
| @Component(property = { "testProperty1=hello", "testProperty2=A", "testProperty2=B", "testProperty2=C" }) | |
| public class ComponentMultivaluedPropertyImpl { | |
| private static final Logger LOGGER = LoggerFactory.getLogger(ComponentMultivaluedPropertyImpl.class); | |
| @Activate | |
| protected void activate(ComponentContext componentContext) { | |
| LOGGER.info("Registering: " + componentContext.getProperties().get("testProperty1").toString()); | |
| Object[] arr = convertToObjectArray(componentContext.getProperties().get("testProperty2")); | |
| for (Object obj : arr) { | |
| LOGGER.info("Registering testProperty2: " + obj); | |
| } | |
| } | |
| @Deactivate | |
| protected void deactivate(ComponentContext componentContext) { | |
| LOGGER.info("Deregistering: " + componentContext.getProperties().get("testProperty1").toString()); | |
| Object[] arr = convertToObjectArray(componentContext.getProperties().get("testProperty2")); | |
| for (Object obj : arr) { | |
| LOGGER.info("DeRegistering testProperty2: " + obj); | |
| } | |
| } | |
| static Object[] convertToObjectArray(Object array) { | |
| Class ofArray = array.getClass().getComponentType(); | |
| if (ofArray.isPrimitive()) { | |
| List ar = new ArrayList(); | |
| int length = Array.getLength(array); | |
| for (int i = 0; i < length; i++) { | |
| ar.add(Array.get(array, i)); | |
| } | |
| return ar.toArray(); | |
| } else { | |
| return (Object[]) array; | |
| } | |
| } | |
| } |
Creating configurable properties
The annotations described in this section will help you to create Components whose configurations can be edited via OSGi console. To achieve the same:
- Create a separate or an inner interface which would hold configurations. In example, we have created Config interface.
- Add @ObjectClassDefinition annotation to the interface. Also, add desired attributes
- name: The name would help you search the configuration in OSGi’s configuration manager.
- Add @Designate to the Component that would consume the configurations. The ocd attribute should refer to the Configuration interface created in Step-2.
- Declare properties that you would like to configure via @AttributeDefinition
- To define property names similar to
blog.name, your method would be namedblog_name - Following image maps annotation attributes with the OSGi UI.

- Please note that there are 2 ways to define default values:
- defaultValue attribute of @AttributeDefinition: The value is displayed to the user, when he/she tries to configure the interface via Configuration manager. OSGi will NOT pick this default value, if no Configuration exists. Thus, when you install a bundle, the output would appear as:

- Specifying default value in variable declarartion: The value is displayed to the user, when he/she tries to configure the interface via Configuration manager. OSGi will pick this default value, even if no Configuration exists.
- defaultValue attribute of @AttributeDefinition: The value is displayed to the user, when he/she tries to configure the interface via Configuration manager. OSGi will NOT pick this default value, if no Configuration exists. Thus, when you install a bundle, the output would appear as:
- To define property names similar to
| package blog.techrevel.component.impl; | |
| import org.osgi.service.component.annotations.Activate; | |
| import org.osgi.service.component.annotations.Component; | |
| import org.osgi.service.metatype.annotations.AttributeDefinition; | |
| import org.osgi.service.metatype.annotations.AttributeType; | |
| import org.osgi.service.metatype.annotations.Designate; | |
| import org.osgi.service.metatype.annotations.ObjectClassDefinition; | |
| import org.osgi.service.metatype.annotations.Option; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| @Component | |
| @Designate(ocd = ConfigurableComponentPorpertiesImpl.Config.class) | |
| public class ConfigurableComponentPorpertiesImpl { | |
| private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurableComponentPorpertiesImpl.class); | |
| @ObjectClassDefinition(name = "Techrevel Sample Configuration", description = "This is sample configuration") | |
| public @interface Config { | |
| @AttributeDefinition(name = "Blog name", defaultValue = "techrevel", description = "Name of the blog") | |
| String blog_name(); | |
| @AttributeDefinition(name = "Blog Url") | |
| String blog_URL() default "https://techrevel.blog"; | |
| // Multi-values property | |
| @AttributeDefinition(name = "Blog Topics") | |
| String[] blog_Topics() default { "OSGi", "AEM" }; | |
| @AttributeDefinition(name = "Blog Count", description = "Total number of blogs", type = AttributeType.INTEGER) | |
| int blogCount() default 0; | |
| // Password | |
| @AttributeDefinition(name = "password", type = AttributeType.PASSWORD) | |
| String password(); | |
| // Checkbox | |
| @AttributeDefinition(name = "Blog is active?") | |
| boolean blogIsActive() default true; | |
| // Dropdown | |
| @AttributeDefinition(name = "Blog is hosted at?", options = { @Option(label = "WordPress", value = "wordpress"), | |
| @Option(label = "Blogspot", value = "blogspot") }) | |
| String hostedAt() default ""; | |
| } | |
| @Activate | |
| protected void activate(final Config config) { | |
| LOGGER.info("Blog name: " + config.blog_name()); | |
| LOGGER.info("Blog URL: " + config.blog_URL()); | |
| for (String topic : config.blog_Topics()) { | |
| LOGGER.info("Blog Topics: " + topic); | |
| } | |
| LOGGER.info("Blog Count: " + config.blogCount()); | |
| LOGGER.info("Blog Password: " + config.password()); | |
| LOGGER.info("Blog Is Active? " + config.blogIsActive()); | |
| LOGGER.info("Blog is hosted at? " + config.hostedAt()); | |
| } | |
| } |
Also, note that we no longer need PropertiesUtil to resolve OSGi configurations. 🙂
Notes:
Via Declarative Services, the number of annotations have been reduced. For example: @Component annotation is used for:
- Component
- Service
- Servlet
- Filter etc..
All of the above can be created by utilizing attributes of @Component details. More details are available on specific links
One thought on “DS Annotations – Component, property and configurations”