From AEM6.2 you can use OSGi anno­ta­tions in your project, instead of the good-old Felix ones. You can still use the Felix anno­ta­tions in your project, but I hope after this arti­cle you are tempt­ed to use the OSGi anno­ta­tions.

In this arti­cle I will describe how to use them, and some advan­tages in your code.

Project changes

In order to use them, make the fol­low­ing changes in your pom.xml

Use 3.2.0 or lat­er for the maven-bun­dle-plu­g­in

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

Add the fol­low­ing depen­den­cies

<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-set­up changed, we can have a look what is changed code­wise.

First change is that @Service and @Component are now com­bined, via ser­vice you spec­i­fy which ser­vice you are imple­ment­ing

@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, defin­ing OSGi prop­er­ties in your code. You can now spec­i­fy a prop­er inter­face which gives you type-safe­ty for free. To end this, there is no need any­more to ‘read’ the prop­er­ties in the @Activate-method.

Let me show you this in code:

Spec­i­fy at class lev­el the object-class-def­i­n­i­tion

@Designate(ocd = MyServiceConfiguration.class)

In your acti­vate-method the inter­face is now your argu­ment, so no need any­more to read and con­vert prop­er­ties.

private MyServiceConfiguration config;

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

The MySer­vice­Con­fig­u­ra­tion is an inter­face, that defines the prop­er­ties 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 set­up will save quite some boil­er­plate code on read­ing / con­vert­ing prop­er­ties.

The con­fig­u­ra­tion from above dis­plays like this in the con­fig­M­gr:

Setting properties

When you need to set prop­er­ties, they are defined via the prop­er­ty[] attribute in the @Component anno­ta­tion. In case you need to set a dif­fer­ent datatype (not String), you can do this via “:<datatype>”.

Here an exam­ple how you can set such prop­er­ties, where for exam­ple the ser­vice-rank­ing is set via an Inte­ger val­ue.

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

Examples

The exam­ples used, you can find here my local pub­lic github, also the AEM Core Com­po­nents can be used as a ref­er­ence:

MySim​ple​Ser​vi​ceIm​pl​.java

MySer​vice​Con​fig​u​ra​tion​.java

AEM Core Com­po­nents

0 comments