Class loading, wiring, and uses constraints
OSGi creates a controlled class space for each bundle.
Delegation
Class lookup generally checks Java/platform boot delegation, the bundle's imports, required bundles, its own content, and dynamic imports according to framework rules. Exact details depend on the source of the request. Do not solve class-loading bugs by adding broad boot delegation.
Class identity
A Java type is identified by binary name plus defining class loader. Two bundles may contain the same class name yet create incompatible types. This explains failures that look impossible on a flat classpath.
Split packages
A split package appears in more than one bundle. It makes ownership unclear and can create inconsistent class spaces. Refactor toward one provider per package.
Uses constraints
An exported API package may expose types from another package. The
resolver's uses:= constraint prevents consumer and provider
from seeing incompatible providers of that related type.
If payments.api exposes Money from
money.api, both sides must use a compatible wire for
money.api. A uses-constraint error is protecting type
identity, not being arbitrary.
Fragments
A fragment attaches content to a host bundle and has no independent lifecycle. Fragments can supply localization, tests, native code, or implementation patches, but increase coupling. Prefer services or normal bundles when possible.
DynamicImport-Package
Dynamic imports postpone package discovery until class loading. They reduce resolver evidence, hurt reproducibility, and turn deployment errors into runtime errors. Use only for deliberate extensibility mechanisms that cannot declare requirements upfront.
Diagnostic sequence
- Read the unresolved requirement exactly.
- Inspect provider exports and versions.
- Ask
bundle:diag,headers, or framework wiring APIs. - Trace uses constraints and duplicate providers.
- Fix metadata or package ownership; do not add wildcard imports.
Feynman check
Why can two objects implement interfaces with identical text and still fail a cast? Because their interface classes came from different defining loaders.