Repository: micronaut-projects/micronaut-core
File: core/src/main/java/io/micronaut/core/io/service/ServiceScanner.java (Java)

Code before:
        String path = "META-INF/micronaut/" + serviceName;

        if (isWebSphereClassLoader()) {
            // Special case WebSphere classloader
            // https://github.com/micronaut-projects/micronaut-core/issues/9905
            return path + "/";
        }

        return path;
    }

    private Enumeration<URL> findStandardServiceConfigs() throws IOException {
        return classLoader.getResources(SoftServiceLoader.META_INF_SERVICES + '/' + serviceName);
    }

    private void findMicronautMetaServiceConfigs(BiConsumer<URI, String> consumer) throws IOException, URISyntaxException {
        String path = buildResourceSearchPath();
        final Enumeration<URL> micronautResources = classLoader.getResources(path);
        Set<URI> uniqueURIs = new LinkedHashSet<>();
        while (micronautResources.hasMoreElements()) {
            URL url = micronautResources.nextElement();
            final URI uri = url.toURI();
            uniqueURIs.add(uri);
        }

        if(uniqueURIs.isEmpty()) {
            FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of(), classLoader);
            Path modulesPath = fs.getPath("modules");
            Files.list(modulesPath)
                .filter(p->!p.getFileName().toString().startsWith("jdk.")) // filter out JDK internal modules
                .filter(p->!p.getFileName().toString().startsWith("java.")) // filter out JDK public modules
                .map(p -> p.resolve(path))
                .filter(Files::exists)
                .map(modulesPath::resolve)
                .map(Path::toUri)
                .forEach(uniqueURIs::add);
            // uri will be jrt:/modules/<module>/META-INF/micronaut/<service>, so we can walk through its files as if it was a directory
        }

        for (URI uri : uniqueURIs) {
            String scheme = uri.getScheme();
            if ("file".equals(scheme)) {
                uri = normalizeFilePath(path, uri);
            }
            // on GraalVM there are spurious extra resources that end with # and then a number
            // we ignore this extra ones
            if (!("resource".equals(scheme) && uri.toString().contains("#"))) {
                consumer.accept(uri, path);
            }
        }
    }

Review comment (suggestion):
Not 100% sure if this emtpy-check is correct. For JLink it is, which was the usecase. In case of combining classpath and modulepath this might need to be revisited, although I wonder if people would do that.

Code after:
    }

    private String buildResourceSearchPath() {
        String path = "META-INF/micronaut/" + serviceName;

        if (isWebSphereClassLoader()) {
            // Special case WebSphere classloader
            // https://github.com/micronaut-projects/micronaut-core/issues/9905
            return path + "/";
        }

        return path;
    }

    private Enumeration<URL> findStandardServiceConfigs() throws IOException {
        return classLoader.getResources(SoftServiceLoader.META_INF_SERVICES + '/' + serviceName);
    }

    private void findMicronautMetaServiceConfigs(BiConsumer<URI, String> consumer) throws IOException, URISyntaxException {
        String path = buildResourceSearchPath();
        final Enumeration<URL> micronautResources = classLoader.getResources(path);
        Set<URI> uniqueURIs = new LinkedHashSet<>();
        while (micronautResources.hasMoreElements()) {
            URL url = micronautResources.nextElement();
            final URI uri = url.toURI();
            uniqueURIs.add(uri);
        }

        if (uniqueURIs.isEmpty()) {
            FileSystem fs = null;
            try {
                fs = FileSystems.getFileSystem(URI.create("jrt:/"));
            } catch (FileSystemNotFoundException | ProviderNotFoundException e) {
                //no-op
            }
            if (fs == null || !fs.isOpen()) {
                try {
                    fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap(), classLoader);
                } catch (IOException | ProviderNotFoundException e) {
                    // not available, probably running in Native Image.
                }
            }
            if (fs != null) {
                Path modulesPath = fs.getPath("modules");
                try (Stream<Path> stream = Files.list(modulesPath)) {
                    stream
                        .filter(p -> !p.getFileName().toString().startsWith("jdk.")) // filter out JDK internal modules
                        .filter(p -> !p.getFileName().toString().startsWith("java.")) // filter out JDK public modules
                        .map(p -> p.resolve(path))
                        .filter(Files::exists)
                        .map(modulesPath::resolve)