I've come across a case where I want to use Blueprint (Aries) to resolve a dependency at run-time and the implementation is defined in the same bundle which requires it and will not be used in any other bundles. I am abstracting the implementation within this bundle to make it easier to mock the dependency when unit testing. If I put this service in its own bundle, it would lead to poor cohesion.
At run-time, the Blueprint says it is waiting for dependencies. How can I use Blueprint to realize dependency injection within a bundle?
<!-- Interface -->
<reference id="modelEntityMapper" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />
<!-- Implementation defined within same bundle -->
<bean id="modelEntityMapperImpl" class="org.example.blog.rest.cxf.server.model.impl.ModelEntityMapperImpl" />
<service ref="modelEntityMapperImpl" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />
<!-- Object which has dependency -->
<bean id="posts" class="org.example.blog.rest.cxf.server.BlogResourceImpl">
<property name="modelEntityMapper" ref="modelEntityMapper" />
</bean>
I just tried the suggestion from @christian-scheider and Blueprint is still waiting for some service to satisfy ModelEntityMapper
The XML
<!-- Interface -->
<reference id="modelEntityMapper" interface="org.example.blog.rest.cxf.server.model.ModelEntityMapper" />
<!-- Implementation defined within same bundle -->
<bean id="modelEntityMapperImpl" class="org.example.blog.rest.cxf.server.model.impl.ModelEntityMapperImpl" />
<!-- Object which has dependency -->
<bean id="posts" class="org.example.blog.rest.cxf.server.BlogResourceImpl">
<property name="modelEntityMapper" ref="modelEntityMapperImpl" />
</bean>
The Log
Bundle rest-cxf-server is waiting for dependencies [(objectClass=org.example.blog.rest.cxf.server.model.ModelEntityMapper)]
I was unable to find detailed documentation on the Aries site related to referencing in bundles, so I'm going to reference the Eclipse Gemini Blueprint implementation documentation (formerly Spring Dynamic Modules). See the warning in section 9.2.1.1 of their documentation. Yes, technically this is related to their implementation, but I believe it's likely a similar story in Aries.
It is an error to declare a mandatory reference to a service that is also exported by the same bundle, this behaviour can cause application context creation to fail through either deadlock or timeout.
In a nutshell you typically either import (reference) an OSGi service or you export an OSGi service in the same bundle, usually you don't try to do both in a single bundle.
If you want this bundle to export a service of type ModelEntityMapper
, then you'll need to export it with the service
element. When other beans need a reference within the same bundle, you would use the ref
attribute like you're using it. In this case, you would not need the reference
element at all, but instead use the service
element.
If you're not going to use the ModelEntityMapper
bean outside of this bundle, you don't need to use a reference
or service
element in the configuration at all. You should be able to use it in the ref
attribute without exporting it as an OSGi service - it's basically a bean internal to that bundle. In this case, you should be able to remove the reference
element altogether: the <bean id="modelEntityMapperImpl" ...
will create a bean internal to the bundle, and the <property name="modelEntityMapper" ref="modelEntityMapperImpl" />
element should be able to use that bean internally to the bundle.
If you want to import a reference of type ModelEntityMapper
from OSGi if available, else use an internally defined fallback, that gets more complicated. You'd have to declare a non-mandatory reference
and inject that reference into your class along with the internally defined bean and then have defaulting logic that checks the availability of them. Alternatively you could just define the implementation in a separate bundle from the interface.