Skip to content

Commit 0c067ed

Browse files
committed
Use alternative to ServiceLoader to load Plugin and PropertyRequiresPlugin
Due to module-path working differently to classpath wrt optional services we need to make this change. Otherwise avaje-inject becomes a hard dependency required by avaje-config, avaje-jsonb, any Plugin in fact. We desire avaje-inject to stay an optional dependency so that currently means that we can not use ServiceLoader with module-path due to https://bugs.openjdk.org/browse/JDK-8299504
1 parent f6e1a90 commit 0c067ed

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

inject/src/main/java/io/avaje/inject/DBeanScopeBuilder.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
import io.avaje.lang.Nullable;
88
import jakarta.inject.Provider;
99

10+
import java.io.*;
1011
import java.lang.reflect.Type;
12+
import java.net.URL;
1113
import java.util.*;
1214
import java.util.function.Consumer;
1315
import java.util.function.Supplier;
16+
import java.util.stream.Collectors;
17+
import java.util.stream.Stream;
1418

1519
import static java.lang.System.Logger.Level.DEBUG;
1620

@@ -187,7 +191,7 @@ private void initClassLoader() {
187191

188192
private void initPropertyPlugin() {
189193
propertyRequiresPlugin =
190-
ServiceLoader.load(PropertyRequiresPlugin.class, classLoader)
194+
serviceLoad(PropertyRequiresPlugin.class)
191195
.findFirst()
192196
.orElse(new DSystemProps());
193197
}
@@ -201,7 +205,7 @@ public BeanScope build() {
201205
initPropertyPlugin();
202206
}
203207

204-
ServiceLoader.load(Plugin.class, classLoader).forEach(plugin -> plugin.apply(this));
208+
serviceLoad(Plugin.class).forEach(plugin -> plugin.apply(this));
205209
// sort factories by dependsOn
206210
FactoryOrder factoryOrder = new FactoryOrder(parent, includeModules, !suppliedBeans.isEmpty());
207211
if (factoryOrder.isEmpty()) {
@@ -228,6 +232,32 @@ public BeanScope build() {
228232
return builder.build(shutdownHook, start);
229233
}
230234

235+
private <P> Stream<P> serviceLoad(Class<P> pluginClass) {
236+
return classLoader
237+
.resources("META-INF/services/" + pluginClass.getCanonicalName())
238+
.flatMap(this::resourceLines)
239+
.map(this::serviceInstance);
240+
}
241+
242+
@SuppressWarnings("unchecked")
243+
private <P> P serviceInstance(String className) {
244+
try {
245+
final var clazz = classLoader.loadClass(className);
246+
return (P) clazz.getDeclaredConstructor().newInstance();
247+
} catch (Throwable e) {
248+
throw new RuntimeException(e);
249+
}
250+
}
251+
252+
private Stream<String> resourceLines(URL url) {
253+
try (InputStream is = url.openStream()) {
254+
final var reader = new LineNumberReader(new InputStreamReader(is));
255+
return reader.lines().collect(Collectors.toList()).stream();
256+
} catch (IOException e) {
257+
throw new UncheckedIOException(e);
258+
}
259+
}
260+
231261
/**
232262
* Return the type that we map the supplied bean to.
233263
*/

0 commit comments

Comments
 (0)