OSGI @Component annotation does not include references required by the base class while extending an existing OSGI service
Asked Answered
B

3

5

I'm trying to extend an OSGI service. The OSGI service that is being extended includes some references and properties. I'm using the new org.osgi.service.component.annotations package. The meta XML generated by the annotations processor of OSGi R6 implementation does not account for the reference and property declarations made in the OSGI service I'm extending.

Apache Felix Maven SCR plugin handles this use case well and the class annotated with Felix annotations includes references and properties of the base class as well.

Is there a way to get this working with the official OSGI annotation implementation. I don't want to fallback to Felix SCR plugin unless I have to as their official website says to move on to the OSGI implementation and this is a new project where SCR plugin is not already in use.

Bawdyhouse answered 5/2, 2018 at 13:36 Comment(3)
is the service you are extending a product service (ships with AEM by default)? or is it a service in your source-code ?Frangipani
It ships with AEM by defaultBawdyhouse
I'd recommend not extending it unless you absolutely have no other choice, those services change with new releases and you don't want to keep updating your service when the AEM service impl changes. Do you mind sharing what service is it ?Frangipani
U
7

The meta XML generated by the annotations processor of OSGi R6 implementation does not account for the reference and property declarations made in the OSGI service I'm extending.

The behaviour you are expecting is down to the build tool you are using to generate the XML, not the annotations themselves. In general it is not a good idea to generate the XML based on annotations found in the parent class. This is because the parent class located at build time may not be the same as the parent class located at runtime. In this situation it is possible that generated injection sites might not actually be present at runtime, causing lots of problems. In fact even if the type is the same, you are referencing private details of the parent class from the subclass.

That warning aside, you are probably using a bnd-based tool, such as the maven-bundle-plugin or bnd-maven-plugin to generate the XML file. To avoid the issues I have mentioned bnd does not search the parent class of a component for annotations, but this behaviour can be overridden in configuration using the following instruction:

-dsannotations-options: inherit

If you add that configuration option then you should see the behaviour that you want, but it is strongly recommended that you do not do this when the parent class and child class are in different bundles.

Urial answered 5/2, 2018 at 15:35 Comment(7)
I tried to pass dsannotations-options = inherit by adding <_dsannotations-options>inherit</dsannotations-options> in the instruction section of the maven-bundle-plugin config. I don't think this was passed to bnd and the resulting XML was still same. Should the configuration be different ? PS: I have dropped the plan to extend the service. Just want to validate this and update the answer with POM config and mark it as correct.Bawdyhouse
From the syntax you've given I'm assuming that you're using the maven-bundle-plugin. Aside from the missing '_' in your closing tag that looks fine. What version of the maven-bundle-plugin are you using? I occasionally see truly ancient versions in use, and this option was only added in bnd 3.0.0 (Sep 2015).Urial
I'm using maven-bundle-plugin. The version is 3.5.0.Bawdyhouse
That should be new enough then. Other things to check are that the class file you're inheriting from is available on the build path when the plugin is running, and that the service you're inheriting from is annotated with the standard annotations (not similar annotations from bnd or Felix which don't mix with the standard)Urial
The base class could be using Felix SCR annotations since that was the standard set up for AEM until now.Bawdyhouse
+1 for this clear explanation. About the recommendation: "it is strongly recommended that you do not do this when the parent class and child class are in different bundles.". Well, there are a lot of bundles that implement API interfaces defined and exported by other bundles. So, in this case, both bundles should be made available in OSGi container in order to work accordingly. In the same situation there may be an abstract parent class defined in a bundle (may be the same where API interfaces are defined) which is extended by another class defined in another bundle.Prehensile
The recommendation above is intended to apply to inheriting DS annotations, not inheritance in general. Inheriting from API types in other bundles (particularly interfaces) is a good thing and I wouldn't want you to think that I am recommending against that. The specific issue here is that you shouldn't try to inherit DS annotation configuration from a super type, and if you do try to do it then you definitely shouldn't try to inherit them across bundle boundaries.Urial
G
2

Another option that doesn't require inheriting annotations from the base class is to redeclare the needed references in the component itself:

@Component(
     service = SomeService.class,
     reference = {
         @Reference(
             name = "baseClassField",
             field = "baseClassField",
             service = SomeOtherService.class
         ),
         @Reference(
             name = "otherBaseClassField",
             field = "otherBaseClassField",
             service = YetAnotherService.class,
             cardinality=ReferenceCardinality.MULTIPLE,
             policy=ReferencePolicy.DYNAMIC
         )
     }
)
public class MyServiceImplementation
    extends AbstractSomeServiceBaseImpl
    implements SomeService
{...}

The obvious disadvantage is that you explicitly hardcode the implementation details of the superclass, which may be even more wrong than implicitly inheriting them at build time. This way not only can the runtime class have different fields than the compile time dependency, but even at compile time when the base class changes you have to make sure to update your class to reflect the added, removed, or renamed fields.

Gilligan answered 28/8, 2019 at 16:37 Comment(0)
R
0

For use in maven you can define in this way:

<plugins>
    <plugin>
        <groupId>biz.aQute.bnd</groupId>
        <artifactId>bnd-maven-plugin</artifactId>
        <version>3.5.0</version>
        <executions>
            <execution>
                <id>run-bnd</id>
                <goals>
                    <goal>bnd-process</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <bnd><![CDATA[-dsannotations-options: inherit]]></bnd>
        </configuration>
    </plugin>
</plugins>
Ration answered 16/5, 2018 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.