Skip to content

Commit aeb777b

Browse files
Internal, only necessary for diffbase
PiperOrigin-RevId: 764912623
1 parent ffa9ca2 commit aeb777b

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

runner/monitor/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
**New Features**
1010

11+
* Adds @Supersedes to ServiceLoaderWrapper so it's possible to choose one
12+
implementation over another when multiple exist.
13+
1114
**Breaking Changes**
1215

1316
**API Changes**

runner/monitor/java/androidx/test/internal/platform/ServiceLoaderWrapper.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import android.os.StrictMode;
1919
import androidx.annotation.RestrictTo;
2020
import java.util.ArrayList;
21+
import java.util.HashSet;
2122
import java.util.List;
2223
import java.util.ServiceLoader;
24+
import java.util.Set;
2325

2426
/**
2527
* Wrapper class for {@link ServiceLoader} that disables StrictMode.
@@ -86,7 +88,7 @@ public static <T> T loadSingleService(Class<T> serviceClass, Factory<T> defaultI
8688
* @throws IllegalStateException if more than one service implementations are found
8789
*/
8890
public static <T> T loadSingleServiceOrNull(Class<T> serviceClass) {
89-
List<T> impls = ServiceLoaderWrapper.loadService(serviceClass);
91+
List<T> impls = filter(ServiceLoaderWrapper.loadService(serviceClass));
9092
if (impls.isEmpty()) {
9193
return null;
9294
} else if (impls.size() == 1) {
@@ -102,4 +104,27 @@ public static <T> T loadSingleServiceOrNull(Class<T> serviceClass) {
102104
"Found more than one implementation for " + serviceClass.getName() + combinedImpls);
103105
}
104106
}
107+
108+
@SuppressWarnings("unchecked")
109+
private static <T> List<T> filter(List<T> services) {
110+
Set<Class<?>> superseded = new HashSet<>();
111+
for (T service : services) {
112+
Class<? extends T> clazz = (Class<? extends T>) service.getClass();
113+
Supersedes supersedes = clazz.getAnnotation(Supersedes.class);
114+
if (supersedes != null) {
115+
superseded.add(supersedes.value());
116+
}
117+
}
118+
if (superseded.isEmpty()) {
119+
return services;
120+
} else {
121+
List<T> filtered = new ArrayList<>();
122+
for (T service : services) {
123+
if (!superseded.contains(service.getClass())) {
124+
filtered.add(service);
125+
}
126+
}
127+
return filtered;
128+
}
129+
}
105130
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package androidx.test.internal.platform;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
/** Indicates that the annotated type is intended as a replacement for another type. */
10+
@Documented
11+
@Retention(RetentionPolicy.RUNTIME)
12+
@Target(ElementType.TYPE)
13+
public @interface Supersedes {
14+
15+
/** The type that is superseded by the annotated type. */
16+
Class<?> value();
17+
}

0 commit comments

Comments
 (0)