Since OSGI R6, developers can improve traditional AEM 6 configurations and create cleaner, more maintainable code. Declarative Services 1.3 (DS 1.3) facilitates this modernization within AEM 6 and Java 8 environments.
Prerequisites
- Verify DS 1.3 is deployed in your OSGI environment
- Create an Apache Maven project baseline
- Specify required dependencies:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>biz.aQute</groupId>
<artifactId>bndlib</artifactId>
<version>1.43.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.component.annotations</artifactId>
<version>1.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>3.3.0</version>
<scope>compile</scope>
</dependency>
- Update Maven plugins for Java 8 and DS 1.3 support:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.23.0</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
The Old Configuration Approach
Traditional AEM configurations embedded properties within component classes. Configuration instantiation required casting and type conversion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Activate
@Modified
protected void init(ComponentContext componentCtx, BundleContext bundleCtx,
Map<String, ?> properties) {
enabled = PropertiesUtil.toBoolean(
componentCtx.getProperties().get(ENABLE_CACHE), true);
heap = PropertiesUtil.toLong(
componentCtx.getProperties().get(CACHE_HEAP), DEFAULT_CACHE_HEAP);
offHeap = PropertiesUtil.toLong(
componentCtx.getProperties().get(CACHE_OFFHEAP),
DEFAULT_CACHE_OFFHEAP);
initialCitiesProp = PropertiesUtil.toStringArray(
componentCtx.getProperties().get(INITIAL_CITIES));
areas = PropertiesUtil.toString(
componentCtx.getProperties().get(ENABLED_CACHE_AREAS), "1");
}
This approach mixes configuration code with business logic, creating bloated classes.
The New Configuration Approach
The modernized strategy separates concerns effectively:
- Create an interface marked with
@ObjectClassDefinitioncontaining all configuration properties with proper type safety and default values - Annotate the implementation class with
@Designateto reference the configuration interface - Inject configuration via
@Activateand@Modifiedmethods:
1
2
3
4
5
6
7
8
private BaseCacheConfig cacheConfig;
@Activate
@Modified
protected void init(ComponentContext componentCtx, BundleContext bundleCtx,
BaseCacheConfig cacheConfig) {
this.cacheConfig = cacheConfig;
}
Conclusions
The new approach reduces class complexity and improves readability. Configuration interfaces become self-documenting. Type safety eliminates casting errors, default values prevent configuration misses, and configurations become reusable across classes, adhering to DRY principles.
Source code examples available on GitHub.