JDK 17 jdk.jdeps.jmod - JDeps Tool

JDK 17 jdk.jdeps.jmod is the JMOD file for JDK 17 JDeps tool, which can be invoked by the "jdeps" command.

JDK 17 JDeps tool compiled class files are stored in \fyicenter\jdk-17.0.5\jmods\jdk.jdeps.jmod.

JDK 17 JDeps tool compiled class files are also linked and stored in the \fyicenter\jdk-17.0.5\lib\modules JImage file.

JDK 17 JDeps tool source code files are stored in \fyicenter\jdk-17.0.5\lib\src.zip\jdk.jdeps.

You can click and view the content of each source code file in the list below.

✍: FYIcenter

com/sun/tools/jdeps/ModuleAnalyzer.java

/*
 * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package com.sun.tools.jdeps;

import static com.sun.tools.jdeps.JdepsFilter.DEFAULT_FILTER;
import static com.sun.tools.jdeps.Module.*;
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
import static java.util.stream.Collectors.*;

import com.sun.tools.classfile.Dependency;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.module.ModuleDescriptor;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Analyze module dependences and compare with module descriptor.
 * Also identify any qualified exports not used by the target module.
 */
public class ModuleAnalyzer {
    private static final String JAVA_BASE = "java.base";

    private final JdepsConfiguration configuration;
    private final PrintWriter log;
    private final DependencyFinder dependencyFinder;
    private final Map<Module, ModuleDeps> modules;

    public ModuleAnalyzer(JdepsConfiguration config,
                          PrintWriter log,
                          Set<String> names) {
        this.configuration = config;
        this.log = log;

        this.dependencyFinder = new DependencyFinder(config, DEFAULT_FILTER);
        if (names.isEmpty()) {
            this.modules = configuration.rootModules().stream()
                .collect(toMap(Function.identity(), ModuleDeps::new));
        } else {
            this.modules = names.stream()
                .map(configuration::findModule)
                .flatMap(Optional::stream)
                .collect(toMap(Function.identity(), ModuleDeps::new));
        }
    }

    public boolean run(boolean ignoreMissingDeps) throws IOException {
        try {
            for (ModuleDeps md: modules.values()) {
                // compute "requires transitive" dependences
                md.computeRequiresTransitive(ignoreMissingDeps);
                // compute "requires" dependences
                md.computeRequires(ignoreMissingDeps);
                // print module descriptor
                md.printModuleDescriptor();

                // apply transitive reduction and reports recommended requires.
                boolean ok = md.analyzeDeps();
                if (!ok) return false;

                if (ignoreMissingDeps && md.hasMissingDependencies()) {
                    log.format("Warning: --ignore-missing-deps specified. Missing dependencies from %s are ignored%n",
                               md.root.name());
                }
            }
        } finally {
            dependencyFinder.shutdown();
        }
        return true;
    }


    class ModuleDeps {
        final Module root;
        Set<Module> requiresTransitive;
        Set<Module> requires;
        Map<String, Set<String>> unusedQualifiedExports;

        ModuleDeps(Module root) {
            this.root = root;
        }

        /**
         * Compute 'requires transitive' dependences by analyzing API dependencies
         */
        private void computeRequiresTransitive(boolean ignoreMissingDeps) {
            // record requires transitive
            this.requiresTransitive = computeRequires(true, ignoreMissingDeps)
                .filter(m -> !m.name().equals(JAVA_BASE))
                .collect(toSet());

            trace("requires transitive: %s%n", requiresTransitive);
        }

        private void computeRequires(boolean ignoreMissingDeps) {
            this.requires = computeRequires(false, ignoreMissingDeps).collect(toSet());
            trace("requires: %s%n", requires);
        }

        private Stream<Module> computeRequires(boolean apionly, boolean ignoreMissingDeps) {
            // analyze all classes
            if (apionly) {
                dependencyFinder.parseExportedAPIs(Stream.of(root));
            } else {
                dependencyFinder.parse(Stream.of(root));
            }

            // find the modules of all the dependencies found
            return dependencyFinder.getDependences(root)
                        .filter(a -> !(ignoreMissingDeps && Analyzer.notFound(a)))
                        .map(Archive::getModule);
        }

        boolean hasMissingDependencies() {
            return dependencyFinder.getDependences(root).anyMatch(Analyzer::notFound);
        }

        ModuleDescriptor descriptor() {
            return descriptor(requiresTransitive, requires);
        }

        private ModuleDescriptor descriptor(Set<Module> requiresTransitive,
                                            Set<Module> requires) {

            ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(root.name());

            if (!root.name().equals(JAVA_BASE))
                builder.requires(Set.of(MANDATED), JAVA_BASE);

            requiresTransitive.stream()
                .filter(m -> !m.name().equals(JAVA_BASE))
                .map(Module::name)
                .forEach(mn -> builder.requires(Set.of(TRANSITIVE), mn));

            requires.stream()
                .filter(m -> !requiresTransitive.contains(m))
                .filter(m -> !m.name().equals(JAVA_BASE))
                .map(Module::name)
                .forEach(mn -> builder.requires(mn));

            return builder.build();
        }

        private Graph<Module> buildReducedGraph() {
            ModuleGraphBuilder rpBuilder = new ModuleGraphBuilder(configuration);
            rpBuilder.addModule(root);
            requiresTransitive.stream()
                          .forEach(m -> rpBuilder.addEdge(root, m));

            // requires transitive graph
            Graph<Module> rbg = rpBuilder.build().reduce();

            ModuleGraphBuilder gb = new ModuleGraphBuilder(configuration);
            gb.addModule(root);
            requires.stream()
                    .forEach(m -> gb.addEdge(root, m));

            // transitive reduction
            Graph<Module> newGraph = gb.buildGraph().reduce(rbg);
            if (DEBUG) {
                System.err.println("after transitive reduction: ");
                newGraph.printGraph(log);
            }
            return newGraph;
        }

        /**
         * Apply the transitive reduction on the module graph
         * and returns the corresponding ModuleDescriptor
         */
        ModuleDescriptor reduced() {
            Graph<Module> g = buildReducedGraph();
            return descriptor(requiresTransitive, g.adjacentNodes(root));
        }

        private void showMissingDeps() {
            // build the analyzer if there are missing dependences
            Analyzer analyzer = new Analyzer(configuration, Analyzer.Type.CLASS, DEFAULT_FILTER);
            analyzer.run(Set.of(root), dependencyFinder.locationToArchive());
            log.println("Error: Missing dependencies: classes not found from the module path.");
            Analyzer.Visitor visitor = new Analyzer.Visitor() {
                @Override
                public void visitDependence(String origin, Archive originArchive, String target, Archive targetArchive) {
                    log.format("   %-50s -> %-50s %s%n", origin, target, targetArchive.getName());
                }
            };
            analyzer.visitDependences(root, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound);
            log.println();
        }

        /**
         * Apply transitive reduction on the resulting graph and reports
         * recommended requires.
         */
        private boolean analyzeDeps() {
            if (requires.stream().anyMatch(m -> m == UNNAMED_MODULE)) {
                showMissingDeps();
                return false;
            }

            ModuleDescriptor analyzedDescriptor = descriptor();
            if (!matches(root.descriptor(), analyzedDescriptor)) {
                log.format("  [Suggested module descriptor for %s]%n", root.name());
                analyzedDescriptor.requires()
                    .stream()
                    .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
                    .forEach(req -> log.format("    requires %s;%n", req));
            }

            ModuleDescriptor reduced = reduced();
            if (!matches(root.descriptor(), reduced)) {
                log.format("  [Transitive reduced graph for %s]%n", root.name());
                reduced.requires()
                    .stream()
                    .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
                    .forEach(req -> log.format("    requires %s;%n", req));
            }

            checkQualifiedExports();
            log.println();
            return true;
        }

        private void checkQualifiedExports() {
            // detect any qualified exports not used by the target module
            unusedQualifiedExports = unusedQualifiedExports();
            if (!unusedQualifiedExports.isEmpty())
                log.format("  [Unused qualified exports in %s]%n", root.name());

            unusedQualifiedExports.keySet().stream()
                .sorted()
                .forEach(pn -> log.format("    exports %s to %s%n", pn,
                    unusedQualifiedExports.get(pn).stream()
                        .sorted()
                        .collect(joining(","))));
        }

        void printModuleDescriptor() {
            printModuleDescriptor(log, root);
        }

        private void printModuleDescriptor(PrintWriter out, Module module) {
            ModuleDescriptor descriptor = module.descriptor();
            out.format("%s (%s)%n", descriptor.name(), module.location());

            if (descriptor.name().equals(JAVA_BASE))
                return;

            out.println("  [Module descriptor]");
            descriptor.requires()
                .stream()
                .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
                .forEach(req -> out.format("    requires %s;%n", req));
        }


        /**
         * Detects any qualified exports not used by the target module.
         */
        private Map<String, Set<String>> unusedQualifiedExports() {
            Map<String, Set<String>> unused = new HashMap<>();

            // build the qualified exports map
            Map<String, Set<String>> qualifiedExports =
                root.exports().entrySet().stream()
                    .filter(e -> !e.getValue().isEmpty())
                    .map(Map.Entry::getKey)
                    .collect(toMap(Function.identity(), _k -> new HashSet<>()));

            Set<Module> mods = new HashSet<>();
            root.exports().values()
                .stream()
                .flatMap(Set::stream)
                .forEach(target -> configuration.findModule(target)
                    .ifPresentOrElse(mods::add,
                        () -> log.format("Warning: %s not found%n", target))
                );

            // parse all target modules
            dependencyFinder.parse(mods.stream());

            // adds to the qualified exports map if a module references it
            mods.stream().forEach(m ->
                m.getDependencies()
                    .map(Dependency.Location::getPackageName)
                    .filter(qualifiedExports::containsKey)
                    .forEach(pn -> qualifiedExports.get(pn).add(m.name())));

            // compare with the exports from ModuleDescriptor
            Set<String> staleQualifiedExports =
                qualifiedExports.keySet().stream()
                    .filter(pn -> !qualifiedExports.get(pn).equals(root.exports().get(pn)))
                    .collect(toSet());

            if (!staleQualifiedExports.isEmpty()) {
                for (String pn : staleQualifiedExports) {
                    Set<String> targets = new HashSet<>(root.exports().get(pn));
                    targets.removeAll(qualifiedExports.get(pn));
                    unused.put(pn, targets);
                }
            }
            return unused;
        }
    }

    private boolean matches(ModuleDescriptor md, ModuleDescriptor other) {
        // build requires transitive from ModuleDescriptor
        Set<ModuleDescriptor.Requires> reqTransitive = md.requires().stream()
            .filter(req -> req.modifiers().contains(TRANSITIVE))
            .collect(toSet());
        Set<ModuleDescriptor.Requires> otherReqTransitive = other.requires().stream()
            .filter(req -> req.modifiers().contains(TRANSITIVE))
            .collect(toSet());

        if (!reqTransitive.equals(otherReqTransitive)) {
            trace("mismatch requires transitive: %s%n", reqTransitive);
            return false;
        }

        Set<ModuleDescriptor.Requires> unused = md.requires().stream()
            .filter(req -> !other.requires().contains(req))
            .collect(Collectors.toSet());

        if (!unused.isEmpty()) {
            trace("mismatch requires: %s%n", unused);
            return false;
        }
        return true;
    }

    // ---- for testing purpose
    public ModuleDescriptor[] descriptors(String name) {
        ModuleDeps moduleDeps = modules.keySet().stream()
            .filter(m -> m.name().equals(name))
            .map(modules::get)
            .findFirst().get();

        ModuleDescriptor[] descriptors = new ModuleDescriptor[3];
        descriptors[0] = moduleDeps.root.descriptor();
        descriptors[1] = moduleDeps.descriptor();
        descriptors[2] = moduleDeps.reduced();
        return descriptors;
    }

    public Map<String, Set<String>> unusedQualifiedExports(String name) {
        ModuleDeps moduleDeps = modules.keySet().stream()
            .filter(m -> m.name().equals(name))
            .map(modules::get)
            .findFirst().get();
        return moduleDeps.unusedQualifiedExports;
    }
}

com/sun/tools/jdeps/ModuleAnalyzer.java

 

Or download all of them as a single archive file:

File name: jdk.jdeps-17.0.5-src.zip
File size: 258425 bytes
Release date: 2022-09-13
Download 

 

JDK 17 jdk.jdi.jmod - JDI Tool

JDK 17 jdk.jconsole.jmod - JConsole Tool

JDK 17 JMod/Module Files

⇑⇑ FAQ for JDK (Java Development Kit) 17

2023-04-17, 6021👍, 0💬