
io.opentelemetry.javaagent.tooling.SafeServiceLoader Maven / Gradle / Ivy
Show all versions of opentelemetry-javaagent-tooling Show documentation
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.tooling;
import static java.util.logging.Level.FINE;
import io.opentelemetry.sdk.autoconfigure.spi.Ordered;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.logging.Logger;
public final class SafeServiceLoader {
private static final Logger logger = Logger.getLogger(SafeServiceLoader.class.getName());
/**
* Delegates to {@link ServiceLoader#load(Class, ClassLoader)} and then eagerly iterates over
* returned {@code Iterable}, ignoring any potential {@link UnsupportedClassVersionError}.
*
* Those errors can happen when some classes returned by {@code ServiceLoader} were compiled
* for later java version than is used by currently running JVM. During normal course of business
* this should not happen. Please read CONTRIBUTING.md, section "Testing - Java versions" for a
* background info why this is Ok.
*/
// Because we want to catch exception per iteration
@SuppressWarnings("ForEachIterable")
public static List load(Class serviceClass, ClassLoader classLoader) {
List result = new ArrayList<>();
ServiceLoader services = ServiceLoader.load(serviceClass, classLoader);
for (Iterator iterator = new SafeIterator<>(services.iterator()); iterator.hasNext(); ) {
T service = iterator.next();
if (service != null) {
result.add(service);
}
}
return result;
}
/**
* Same as {@link #load(Class, ClassLoader)}, but also orders the returned implementations by
* comparing their {@link Ordered#order()}.
*/
public static List loadOrdered(
Class serviceClass, ClassLoader classLoader) {
List result = load(serviceClass, classLoader);
result.sort(Comparator.comparing(Ordered::order));
return result;
}
private SafeServiceLoader() {}
private static class SafeIterator implements Iterator {
private final Iterator delegate;
SafeIterator(Iterator iterator) {
delegate = iterator;
}
private static void handleUnsupportedClassVersionError(
UnsupportedClassVersionError unsupportedClassVersionError) {
logger.log(
FINE,
"Unable to load instrumentation class: {0}",
unsupportedClassVersionError.getMessage());
}
@Override
public boolean hasNext() {
// jdk9 and newer throw UnsupportedClassVersionError in hasNext()
while (true) {
try {
return delegate.hasNext();
} catch (UnsupportedClassVersionError unsupportedClassVersionError) {
handleUnsupportedClassVersionError(unsupportedClassVersionError);
}
}
}
@Override
public T next() {
// jdk8 throws UnsupportedClassVersionError in next()
try {
return delegate.next();
} catch (UnsupportedClassVersionError unsupportedClassVersionError) {
handleUnsupportedClassVersionError(unsupportedClassVersionError);
return null;
}
}
}
}