From AEM6.2 you can use OSGi R6 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.
From AEM6.4 you can use the OSGi R7 annotations: http://blogs.adobe.com/experiencedelivers/experience-management/osgi/using-osgi-r7-annotations-aem/
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 public github, also the AEM Core Components can be used as a reference:
MySimpleServiceImpl.java