This is the documentation of the Eclipse Equinox Framework.
Boot delegation in the Equinox OSGi Framework controls which classes can be loaded directly from the parent (boot) classloader, bypassing the normal OSGi class loading mechanism. This feature is particularly important when dealing with JDK classes and framework extensions.
In a standard OSGi environment, each bundle has its own classloader and explicitly declares its dependencies through Import-Package or Require-Bundle headers. However, there are scenarios where bundles need access to classes from the boot classpath (JDK classes, VM-provided classes) without explicitly importing them.
When a bundle attempts to load a class, the Equinox framework follows the OSGi delegation model:
The boot delegation mechanism operates at step 2, allowing early delegation to the parent classloader for specified packages.
The primary property for configuring boot delegation is org.osgi.framework.bootdelegation. This property accepts a comma-separated list of package names that should be delegated to the parent classloader.
Syntax:
org.osgi.framework.bootdelegation=package1,package2.*,package3.subpackage
Examples:
Delegate specific package:
org.osgi.framework.bootdelegation=sun.reflect
Delegate package and all subpackages (using wildcard):
org.osgi.framework.bootdelegation=sun.reflect.*
Delegate all packages:
org.osgi.framework.bootdelegation=*
Delegate multiple packages:
org.osgi.framework.bootdelegation=sun.reflect,sun.misc,com.sun.*
Wildcard Rules:
package.* - Matches the package and all its subpackages (e.g., sun.reflect.* matches sun.reflect.Reflection and sun.reflect.generics.Reflector)package - Matches only the exact package (e.g., sun.reflect matches only classes directly in sun.reflect)* - Matches all packages (use with caution as it can bypass OSGi modularization)The osgi.compatibility.bootdelegation property provides backward compatibility for older applications that relied on implicit boot delegation.
Values:
true - Enable compatibility mode (try parent classloader as last resort)false - Disable compatibility mode (default for embedded frameworks)Default behavior:
truefalseWhen enabled, this property allows bundles to load classes from the boot classpath even if they don’t explicitly import them and the class is not in the boot delegation list. This happens as a last resort after all other class loading mechanisms have been attempted.
Example in config.ini:
osgi.compatibility.bootdelegation=false
Example programmatically:
Map<String, Object> configuration = new HashMap<>();
configuration.put("osgi.compatibility.bootdelegation", "true");
Equinox equinox = new Equinox(configuration);
The osgi.context.bootdelegation property controls whether boot delegation is enabled when loading classes from the context classloader.
Values:
true - Enable context boot delegation (default)false - Disable context boot delegationDefault: true
This property is particularly useful when dealing with thread context classloaders and class loading that happens outside the normal bundle classloader chain.
This property controls how the org.osgi.framework.bootdelegation property defined in Java profiles should be processed.
Values:
ignore - Ignore boot delegation from Java profile (default)override - Java profile boot delegation overrides system propertynone - Ignore boot delegation from both Java profile and system propertiesDefault: ignore
Some applications need access to internal JDK classes that are not part of the standard exported API.
org.osgi.framework.bootdelegation=sun.misc,sun.reflect.*,com.sun.jndi.*
Note: Relying on internal JDK classes is discouraged as they may change or be removed in future Java versions. Use with caution and consider alternatives.
When using framework extensions that add classes to the system bundle, boot delegation may be needed to ensure proper access.
During testing, you may want to allow bundles to access test framework classes from the boot classpath:
org.osgi.framework.bootdelegation=org.junit.*,org.hamcrest.*
When migrating legacy applications to OSGi, boot delegation can provide a temporary bridge:
osgi.compatibility.bootdelegation=true
However, this should be a temporary measure. The long-term solution is to properly modularize the application with correct Import-Package declarations.
In an Eclipse installation, edit the configuration/config.ini file:
org.osgi.framework.bootdelegation=sun.reflect,sun.misc.*
osgi.compatibility.bootdelegation=false
When embedding Equinox:
Map<String, Object> configuration = new HashMap<>();
configuration.put(Constants.FRAMEWORK_BOOTDELEGATION, "sun.reflect,sun.misc.*");
configuration.put("osgi.compatibility.bootdelegation", "false");
Equinox equinox = new Equinox(configuration);
equinox.start();
Boot delegation can also be configured via system properties:
java -Dorg.osgi.framework.bootdelegation=sun.reflect,sun.misc.* -jar org.eclipse.osgi.jar
When starting Eclipse:
eclipse -vmargs -Dorg.osgi.framework.bootdelegation=sun.reflect.*
Recommendation: Use boot delegation sparingly. Over-reliance on boot delegation defeats the purpose of OSGi modularization.
Why: Boot delegation bypasses the explicit dependency management that makes OSGi valuable. It can lead to:
Instead of relying on boot delegation, bundles should explicitly declare their dependencies:
Import-Package: sun.misc;resolution:=optional
This makes dependencies explicit and allows the OSGi framework to properly manage versions and resolve conflicts.
Avoid using wildcards unnecessarily:
Good:
org.osgi.framework.bootdelegation=sun.misc.Unsafe
Acceptable:
org.osgi.framework.bootdelegation=sun.misc.*
Avoid:
org.osgi.framework.bootdelegation=*
Using * delegates all packages to the boot classloader, which can cause:
When using boot delegation, document the reason in your configuration:
# Required for legacy JNDI integration
org.osgi.framework.bootdelegation=com.sun.jndi.*
During development, test your bundles without boot delegation to identify missing imports:
osgi.compatibility.bootdelegation=false
This helps identify missing Import-Package declarations that should be added to your manifest.
Symptom: Bundle throws ClassNotFoundException even though the package is in boot delegation list.
Possible causes:
package.* not just package*Solution:
org.osgi.framework.bootdelegationSymptom: Wrong version of a class is loaded when boot delegation is enabled.
Possible cause: Boot delegation loads the class from the parent classloader instead of the version bundled with your application.
Solution:
Symptom: Slow class loading or startup time.
Possible cause: Using * for boot delegation causes all class loading to attempt parent delegation first.
Solution:
* with specific packagesSymptom: Classes are loaded from unexpected locations.
Possible cause: osgi.compatibility.bootdelegation=true allows fallback to boot classloader.
Solution:
osgi.compatibility.bootdelegation=false to enforce strict OSGi class loadingbundle <id> command in OSGi console to inspect bundle wiringTo debug boot delegation issues, enable OSGi debug tracing:
In config.ini:
osgi.debug=true
osgi.debug.loader=true
Create .options file:
org.eclipse.osgi/debug=true
org.eclipse.osgi/debug/loader=true
org.eclipse.osgi/debug/classloader=true
Then start with:
eclipse -debug .options
Start Eclipse with the OSGi console to inspect bundle wiring:
eclipse -console
Useful commands:
ss - Show all bundles and their statesbundle <id> - Show detailed information about a bundlediag <id> - Diagnose why a bundle is not resolvedpackages <package> - Show which bundles provide/import a packageTo test if a package is in the boot delegation list:
Example test code:
try {
Class<?> clazz = bundle.loadClass("sun.misc.Unsafe");
System.out.println("Boot delegation working for sun.misc");
} catch (ClassNotFoundException e) {
System.out.println("Boot delegation not configured for sun.misc");
}
The boot delegation mechanism in Equinox is implemented in the BundleLoader class. When a bundle attempts to load a class, the framework:
ClassNotFoundException, continues with normal OSGi delegationosgi.compatibility.bootdelegation=true), tries parent classloader again after all other mechanisms failThe boot delegation list is configured during framework initialization and is compiled into efficient data structures:
HashSet for O(1) lookup* is handled as a boolean flag for efficiencyWhen migrating existing Java applications to OSGi, you may encounter class loading issues. Here’s a migration strategy:
osgi.compatibility.bootdelegation=true
org.osgi.framework.bootdelegation=sun.*,com.sun.*
osgi.compatibility.bootdelegation=falseosgi.compatibility.bootdelegation settingThe final goal is to eliminate boot delegation entirely by:
Boot delegation relies on the parent classloader, which is typically the application classloader that loaded the OSGi framework. This classloader has access to:
Framework extensions are fragments to the system bundle that can add classes to the framework classpath. These classes are available through boot delegation.
Understanding OSGi class loading order is crucial for using boot delegation effectively:
| Aspect | Import-Package | Boot Delegation |
|---|---|---|
| Explicitness | Explicit dependency | Implicit dependency |
| Version control | Supports version ranges | No version control |
| OSGi visibility | Follows OSGi rules | Bypasses OSGi |
| Best practice | Recommended | Use sparingly |
| Performance | Optimized | Additional lookup overhead |
Configure only essential internal classes:
config.ini:
org.osgi.framework.bootdelegation=sun.misc.Unsafe
osgi.compatibility.bootdelegation=false
Allow test frameworks to be boot delegated for easier test setup:
config.ini for testing:
org.osgi.framework.bootdelegation=org.junit.*,org.hamcrest.*,org.mockito.*
osgi.compatibility.bootdelegation=false
Temporary configuration for legacy application migration:
config.ini:
org.osgi.framework.bootdelegation=sun.*,com.sun.*,javax.xml.ws.*
osgi.compatibility.bootdelegation=true
Configure boot delegation when embedding Equinox programmatically:
import org.eclipse.osgi.launch.Equinox;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import java.util.HashMap;
import java.util.Map;
public class EmbeddedEquinoxExample {
public static void main(String[] args) throws Exception {
Map<String, Object> config = new HashMap<>();
// Configure storage location
config.put(Constants.FRAMEWORK_STORAGE, "./osgi-cache");
// Configure boot delegation
config.put(Constants.FRAMEWORK_BOOTDELEGATION, "sun.reflect,sun.misc.*");
// Disable compatibility boot delegation for strict OSGi behavior
config.put("osgi.compatibility.bootdelegation", "false");
// Create and start framework
Framework framework = new Equinox(config);
framework.start();
// Use framework...
framework.stop();
framework.waitForStop(0);
}
}
Enable detailed logging to understand class loading:
config.ini:
org.osgi.framework.bootdelegation=sun.misc.*
osgi.debug=true
eclipse.consoleLog=true
.options:
org.eclipse.osgi/debug=true
org.eclipse.osgi/debug/loader=true
org.eclipse.osgi/debug/classloader=true
org.eclipse.osgi/debug/loader/findClass=true
The boot delegation behavior is specified in the OSGi Core Specification:
Key classes in the Equinox implementation:
org.eclipse.osgi.internal.framework.EquinoxContainer - Initializes boot delegation configurationorg.eclipse.osgi.internal.loader.BundleLoader - Implements class loading with boot delegationorg.eclipse.osgi.internal.framework.EquinoxConfiguration - Manages configuration propertiesOther class loading related properties:
osgi.parentClassloader - Controls parent classloader selection (boot, ext, app, fwk)osgi.framework.extensions - Specifies framework extension bundlesosgi.context.bootdelegation - Controls context classloader boot delegation