From AEM6.2 you can use OSGi annotations in your project, instead of the good-old Felix ones. You can still use the Felix annotations in your project, but I hope after this article you are tempted to use the OSGi annotations.

In this article I will describe how to use them, and some advantages in your code.

Project changes

In order to use them, make the following changes in your pom.xml

Use 3.2.0 or later for the maven-bundle-plugin

<plugin>
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <version>3.2.0</version>
  <inherited>true</inherited>
</plugin>

Add the following dependencies

<dependency>
  <groupId>org.osgi</groupId>
  <artifactId>org.osgi.service.component.annotations</artifactId>
  <version>1.3.0</version>
</dependency>

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

<dependency>
  <groupId>org.osgi</groupId>
  <artifactId>org.osgi.service.metatype.annotations</artifactId>
  <version>1.3.0</version>
</dependency>

Changes

Once you got the project-setup changed, we can have a look what is changed codewise.

First change is that @Service and @Component are now combined, via service you specify which service you are implementing

@Component(service = MySimpleService.class)

Still @Reference remains the same

@Reference
private SlingSettingsService settings;

Only thing here is that the imports have changed, they are now:

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;

For me the biggest change is around @Properties / @Property, defining OSGi properties in your code. You can now specify a proper interface which gives you type-safety for free. To end this, there is no need anymore to ‘read’ the properties in the @Activate-method.

Let me show you this in code:

Specify at class level the object-class-definition

@Designate(ocd = MyServiceConfiguration.class)

In your activate-method the interface is now your argument, so no need anymore to read and convert properties.

private MyServiceConfiguration config;

@Activate
public void activate(MyServiceConfiguration config) {
  this.config = config;
}

The MyServiceConfiguration is an interface, that defines the properties and their types.

@ObjectClassDefinition(name = "My Service Configuration", description = "Service Configuration")
public @interface MyServiceConfiguration {

  @AttributeDefinition(name = "Config Value", description = "Configuration value")
  String configValue();

  @AttributeDefinition(name = "MultipleValues", description = "Multi Configuration values")
  String[] getStringValues();

  @AttributeDefinition(name = "NumberValue", description = "Number values", type=AttributeType.INTEGER)
  int getNumberValue();
}

This setup will save quite some boilerplate code on reading / converting properties.

The configuration from above displays like this in the configMgr:

Setting properties

When you need to set properties, they are defined via the property[] attribute in the @Component annotation. In case you need to set a different datatype (not String), you can do this via “:<datatype>”.

Here an example how you can set such properties, where for example the service-ranking is set via an Integer value.

@Component(immediate = true, service=BindingsValuesProvider.class, 
 property={"javax.script.name=sightly", Constants.SERVICE_RANKING +":Integer=1001"})

Examples

The examples used, you can find here my local public github, also the AEM Core Components can be used as a reference:

MySimpleServiceImpl.java

MyServiceConfiguration.java

AEM Core Components

0 comments