Describe the bug
LazyStorage's static initializer block calls ServiceLoader.load(), which in turn uses the Thread context classloader.
This easily becomes inconsistent in multi-classloader applications, where the Class reference passed to the method is from LazyStorage's context but the Thread context classloader (not easily controlled by the application due to how class initializers are invoked in separate, anonymous threads) may be inconsistent and
Steps to reproduce
Most of the work here is creating an application with its own application classpath and modules therein.
With that in place (any arbitrary application will do), set a breakpoint at the start of the LazyStorage static block, and call the following prior to resuming the app:
Thread.currentThread.setContextClassLoader(new URLClassLoader(LazyStorage.class.getClassLoader().getURLs(), LazyStorage.class.getClassLoader().getParent()))
The call to ServiceLoader.load() should then throw a ServiceConfigurationError stating java.util.serviceConfigurationError: io.opentelemetry.context.ContextStorageProvider: io.opentelementry.sdk.testing.context.SettableContextStorageProvider is not a subtype.
What did you expect to see?
LazyStorage initializes without throwing.
What did you see instead?
java.util.serviceConfigurationError as above.
What version and what artifacts are you using?
Orthgonal to bug.
Environment
Orthogonal to bug.
Additional context
Affected application is using a separate URLClassLoader around a 3P dependency that then depends on OpenTelemetry. As above the Thread context classloader when LazyStorage it initialized is not controlled by the application and uses the application default classloader, which is incompatible with the classloader visible to/inherited by LazyStorage.
This bug can also be inelegantly mitigated by setting the system property io.opentelemetry.context.contextStorageProvider to default, however this is in no way guaranteed to continue to bypass the call to ServiceLoader.load() in future LazyStorage code.
Describe the bug
LazyStorage's static initializer block calls ServiceLoader.load(), which in turn uses the Thread context classloader.
This easily becomes inconsistent in multi-classloader applications, where the Class reference passed to the method is from LazyStorage's context but the Thread context classloader (not easily controlled by the application due to how class initializers are invoked in separate, anonymous threads) may be inconsistent and
Steps to reproduce
Most of the work here is creating an application with its own application classpath and modules therein.
With that in place (any arbitrary application will do), set a breakpoint at the start of the LazyStorage static block, and call the following prior to resuming the app:
The call to ServiceLoader.load() should then throw a ServiceConfigurationError stating
java.util.serviceConfigurationError: io.opentelemetry.context.ContextStorageProvider: io.opentelementry.sdk.testing.context.SettableContextStorageProvider is not a subtype.What did you expect to see?
LazyStorage initializes without throwing.
What did you see instead?
java.util.serviceConfigurationError as above.
What version and what artifacts are you using?
Orthgonal to bug.
Environment
Orthogonal to bug.
Additional context
Affected application is using a separate URLClassLoader around a 3P dependency that then depends on OpenTelemetry. As above the Thread context classloader when LazyStorage it initialized is not controlled by the application and uses the application default classloader, which is incompatible with the classloader visible to/inherited by LazyStorage.
This bug can also be inelegantly mitigated by setting the system property
io.opentelemetry.context.contextStorageProvidertodefault, however this is in no way guaranteed to continue to bypass the call toServiceLoader.load()in future LazyStorage code.