Search code examples
javaosgideclarative-services

Reflecting on an OSGI DS @Reference in a ServiceFactory/PrototypeServiceFactory?


I'd like to be able to reflect on a field that has been marked @Reference in OSGI Declarative Services / Apache Felix SCR within a ServiceFactory. (This is research so I'm interested in both what is possible and what is practical).

When an object is constructed in ServiceFactory, there does not seem to be any way to reflect back on the object or field that referenced it it.

public class MyFactory implements PrototypeServiceFactory<MyComponent> {
    @Override
    public Consumer getService(Bundle bundle, ServiceRegistration registration) {
       ...
    }
}

Dictionary<String, String> props = new Hashtable<String, String>();
props.put("class", MyComponent.class.getCanonicalName());
ctx.registerService(MyComponent.class.getCanonicalName(), new MyFactory(), props);

@Component
public class MyOtherComponent {
  @Reference(name = "...", scope = ReferenceScope.PROTOTYPE_REQUIRED)
  private MyComponent myComponent;
}

When I'm in getService with my Bundle and ServiceRegistration, is there any way to understand what the referencing object is? That it was grabbed from MyOtherComponent?

I know @Reference is gone (compile-time only) and ServiceRegistration points to the registration of MyFactory.

I could use bundle to differentiate. But only if a bundle has a single @Reference to MyComponent. Proxying is also an option, every object gets a proxy which dispatches based on the calling stack (This would be messy and slow, correct?)

I was additionally able to do to this manually, by looking at UNSATISFIED_REFERENCES after the fact. This still has lots of edge cases and requires every @Reference have a custom name. https://gist.github.com/sheenobu/004c4ba6effed233bd852f2b45ce9825. And as far as I know I can't use ServiceComponentRuntime to update @Reference's after the fact.

Ultimately, I'd like to be able to do something like Guice, where we have runtime annotations as filters/inputs for referenced objects. (I did try Eclipse Sisu as an alternative to Declarative Services).

@Reference @Something(...)
private MyComponent myComponent; 
   // myComponent is constructed / looked up based on 
   // @Something, within a smart OSGI ServiceFactory. 

Solution

  • When I'm in getService with my Bundle and ServiceRegistration, is there any way to understand what the referencing object is?

    Not in any general way. Just like an object under construction does not know the who is constructing it.

    In these cases, you can attempt to infer the creator from the stack but this is hard since it depends upon how the object is created.

    In the DS case, the object can be created before the receiver is created (this is necessary for constructor injection). So there is no one on the stack to infer.

    Proxying is also an option, every object gets a proxy which dispatches based on the calling stack (This would be messy and slow, correct?)

    This may be your only option. But you still would be infering the receiver based upon the caller which may not actually be the case since the object may be called deeper in a call stack from the actual receiver.