The primary reason is that OSGi is a specification for a reusable component system. If you try to do that with transitive dependencies, you'll find you run into problems at assembly time:
- version conflicts – Component A uses version 1 of X, component B uses version 2 of X. These conflicts are often tapered over in transitive systems like Maven but time bombs are lurking to go off.
- environment dependencies – Some components depend on Windows, other on Linux. Very hard to reconcile these differences.
- version compatibility – Often components could be working together but their transitive dependencies make it impossible.
To address this problem, OSGi invented the service model. The service model allows a component to depend on an API. Once you depend on an API, you no longer have transitive dependencies since transitive dependencies are almost all about implementation dependencies. There is, of course, a dependency on the API, but that has become fuzzier since it is both the consumer of the API and the provider of the API depend on this. This fundamentally changes the dependency model for the better, but very few people grasp this.
I.e. in the service model, the buck stops at the service API. You compile against the API and you can write a lot of test cases against the API. However, your component should never depend on a specific implementation. The first time your component sees an implementation should be in a runtime.
Of course, this forfeits some convenience at the early stages of development. Where in a transitive model, like Maven, things are supposed to compile out of the box, in bnd you need to think about your, and your component's, dependencies ahead of time. This is inconvenient and annoys Maven users, but it is a requirement to make components reusable in very different environments. Maven tends to lock the runtime in often incompatible configurations, in OSGi you do not want the runtime to have any unnecessary restrictions to maximize the reusability of your components.
Putting this restriction on developers, no implementation dependencies, is often too much for developers used to the short term convenience of transitive dependencies. However, developers that embrace this model quickly see that it opens up a vista of possibilities later in the development cycle and reduces a significant of maintenance. Even I am sometimes tempted to skip this level of indirection but somehow, at even slight complexity, I revert because the model has so many advantages on the macro level.
I've been involved in many complex systems and in virtually all cases a lot of complexity in disappears when you kill the transitive dependency sirens.