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.

Sharath Madappa
  • 3,393
  • 1
  • 24
  • 41
  • is the service you are extending a product service (ships with AEM by default)? or is it a service in your source-code ? – Ahmed Musallam Feb 05 '18 at 18:11
  • It ships with AEM by default – Sharath Madappa Feb 05 '18 at 18:12
  • 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 ? – Ahmed Musallam Feb 05 '18 at 18:14

3 Answers3

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.

Tim Ward
  • 1,169
  • 8
  • 9
  • I tried to pass dsannotations-options = inherit by adding <_dsannotations-options>inherit 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. – Sharath Madappa Feb 07 '18 at 08:35
  • 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). – Tim Ward Feb 07 '18 at 10:16
  • I'm using maven-bundle-plugin. The version is 3.5.0. – Sharath Madappa Feb 07 '18 at 10:19
  • 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) – Tim Ward Feb 07 '18 at 10:24
  • The base class could be using Felix SCR annotations since that was the standard set up for AEM until now. – Sharath Madappa Feb 07 '18 at 10:27
  • +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. – bitfox Jul 05 '20 at 10:23
  • 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. – Tim Ward Jul 14 '20 at 14:02
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.

Sergiu Dumitriu
  • 11,455
  • 3
  • 39
  • 62
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>
Bentaye
  • 9,403
  • 5
  • 32
  • 45