JDK 11 jdk.jdeps.jmod - JDeps Tool

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

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

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

JDK 11 JDeps tool source code files are stored in \fyicenter\jdk-11.0.1\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/DepsAnalyzer.java

/*
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.tools.jdeps;

import com.sun.tools.classfile.Dependency.Location;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.sun.tools.jdeps.Analyzer.Type.CLASS;
import static com.sun.tools.jdeps.Analyzer.Type.VERBOSE;
import static com.sun.tools.jdeps.Module.trace;
import static java.util.stream.Collectors.*;

/**
 * Dependency Analyzer.
 *
 * Type of filters:
 * source filter: -include <pattern>
 * target filter: -package, -regex, --require
 *
 * The initial archive set for analysis includes
 * 1. archives specified in the command line arguments
 * 2. observable modules matching the source filter
 * 3. classpath archives matching the source filter or target filter
 * 4. --add-modules and -m root modules
 */
public class DepsAnalyzer {
    final JdepsConfiguration configuration;
    final JdepsFilter filter;
    final JdepsWriter writer;
    final Analyzer.Type verbose;
    final boolean apiOnly;

    final DependencyFinder finder;
    final Analyzer analyzer;
    final List<Archive> rootArchives = new ArrayList<>();

    // parsed archives
    final Set<Archive> archives = new LinkedHashSet<>();

    public DepsAnalyzer(JdepsConfiguration config,
                        JdepsFilter filter,
                        JdepsWriter writer,
                        Analyzer.Type verbose,
                        boolean apiOnly) {
        this.configuration = config;
        this.filter = filter;
        this.writer = writer;
        this.verbose = verbose;
        this.apiOnly = apiOnly;

        this.finder = new DependencyFinder(config, filter);
        this.analyzer = new Analyzer(configuration, verbose, filter);

        // determine initial archives to be analyzed
        this.rootArchives.addAll(configuration.initialArchives());

        // if -include pattern is specified, add the matching archives on
        // classpath to the root archives
        if (filter.hasIncludePattern() || filter.hasTargetFilter()) {
            configuration.getModules().values().stream()
                .filter(source -> include(source) && filter.matches(source))
                .forEach(this.rootArchives::add);
        }

        // class path archives
        configuration.classPathArchives().stream()
            .filter(filter::matches)
            .forEach(this.rootArchives::add);

        // Include the root modules for analysis
        this.rootArchives.addAll(configuration.rootModules());

        trace("analyze root archives: %s%n", this.rootArchives);
    }

    /*
     * Perform runtime dependency analysis
     */
    public boolean run() throws IOException {
        return run(false, 1);
    }

    /**
     * Perform compile-time view or run-time view dependency analysis.
     *
     * @param compileTimeView
     * @param maxDepth  depth of recursive analysis.  depth == 0 if -R is set
     */
    public boolean run(boolean compileTimeView, int maxDepth) throws IOException {
        try {
            // parse each packaged module or classpath archive
            if (apiOnly) {
                finder.parseExportedAPIs(rootArchives.stream());
            } else {
                finder.parse(rootArchives.stream());
            }
            archives.addAll(rootArchives);

            int depth = maxDepth > 0 ? maxDepth : Integer.MAX_VALUE;

            // transitive analysis
            if (depth > 1) {
                if (compileTimeView)
                    transitiveArchiveDeps(depth-1);
                else
                    transitiveDeps(depth-1);
            }

            Set<Archive> archives = archives();

            // analyze the dependencies collected
            analyzer.run(archives, finder.locationToArchive());

            if (writer != null) {
                writer.generateOutput(archives, analyzer);
            }
        } finally {
            finder.shutdown();
        }
        return true;
    }

    /**
     * Returns the archives for reporting that has matching dependences.
     *
     * If --require is set, they should be excluded.
     */
    Set<Archive> archives() {
        if (filter.requiresFilter().isEmpty()) {
            return archives.stream()
                .filter(this::include)
                .filter(Archive::hasDependences)
                .collect(Collectors.toSet());
        } else {
            // use the archives that have dependences and not specified in --require
            return archives.stream()
                .filter(this::include)
                .filter(source -> !filter.requiresFilter().contains(source.getName()))
                .filter(source ->
                        source.getDependencies()
                              .map(finder::locationToArchive)
                              .anyMatch(a -> a != source))
                .collect(Collectors.toSet());
        }
    }

    /**
     * Returns the dependences, either class name or package name
     * as specified in the given verbose level.
     */
    Set<String> dependences() {
        return analyzer.archives().stream()
                       .map(analyzer::dependences)
                       .flatMap(Set::stream)
                       .collect(Collectors.toSet());
    }

    /**
     * Returns the archives that contains the given locations and
     * not parsed and analyzed.
     */
    private Set<Archive> unresolvedArchives(Stream<Location> locations) {
        return locations.filter(l -> !finder.isParsed(l))
                        .distinct()
                        .map(configuration::findClass)
                        .flatMap(Optional::stream)
                        .collect(toSet());
    }

    /*
     * Recursively analyzes entire module/archives.
    */
    private void transitiveArchiveDeps(int depth) throws IOException {
        Stream<Location> deps = archives.stream()
                                        .flatMap(Archive::getDependencies);

        // start with the unresolved archives
        Set<Archive> unresolved = unresolvedArchives(deps);
        do {
            // parse all unresolved archives
            Set<Location> targets = apiOnly
                ? finder.parseExportedAPIs(unresolved.stream())
                : finder.parse(unresolved.stream());
            archives.addAll(unresolved);

            // Add dependencies to the next batch for analysis
            unresolved = unresolvedArchives(targets.stream());
        } while (!unresolved.isEmpty() && depth-- > 0);
    }

    /*
     * Recursively analyze the class dependences
     */
    private void transitiveDeps(int depth) throws IOException {
        Stream<Location> deps = archives.stream()
                                        .flatMap(Archive::getDependencies);

        Deque<Location> unresolved = deps.collect(Collectors.toCollection(LinkedList::new));
        ConcurrentLinkedDeque<Location> deque = new ConcurrentLinkedDeque<>();
        do {
            Location target;
            while ((target = unresolved.poll()) != null) {
                if (finder.isParsed(target))
                    continue;

                Archive archive = configuration.findClass(target).orElse(null);
                if (archive != null) {
                    archives.add(archive);

                    String name = target.getName();
                    Set<Location> targets = apiOnly
                            ? finder.parseExportedAPIs(archive, name)
                            : finder.parse(archive, name);

                    // build unresolved dependencies
                    targets.stream()
                           .filter(t -> !finder.isParsed(t))
                           .forEach(deque::add);
                }
            }
            unresolved = deque;
            deque = new ConcurrentLinkedDeque<>();
        } while (!unresolved.isEmpty() && depth-- > 0);
    }

    /*
     * Tests if the given archive is requested for analysis.
     * It includes the root modules specified in --module, --add-modules
     * or modules specified on the command line
     *
     * This filters system module by default unless they are explicitly
     * requested.
     */
    public boolean include(Archive source) {
        Module module = source.getModule();
        // skip system module by default
        return  !module.isSystem()
                    || configuration.rootModules().contains(source);
    }

    // ----- for testing purpose -----

    public static enum Info {
        REQUIRES,
        REQUIRES_TRANSITIVE,
        EXPORTED_API,
        MODULE_PRIVATE,
        QUALIFIED_EXPORTED_API,
        INTERNAL_API,
        JDK_INTERNAL_API,
        JDK_REMOVED_INTERNAL_API
    }

    public static class Node {
        public final String name;
        public final String source;
        public final Info info;
        Node(String name, Info info) {
            this(name, name, info);
        }
        Node(String name, String source, Info info) {
            this.name = name;
            this.source = source;
            this.info = info;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            if (info != Info.REQUIRES && info != Info.REQUIRES_TRANSITIVE)
                sb.append(source).append("/");

            sb.append(name);
            if (info == Info.QUALIFIED_EXPORTED_API)
                sb.append(" (qualified)");
            else if (info == Info.JDK_INTERNAL_API)
                sb.append(" (JDK internal)");
            else if (info == Info.INTERNAL_API)
                sb.append(" (internal)");
            return sb.toString();
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof Node))
                return false;

            Node other = (Node)o;
            return this.name.equals(other.name) &&
                    this.source.equals(other.source) &&
                    this.info.equals(other.info);
        }

        @Override
        public int hashCode() {
            int result = name.hashCode();
            result = 31 * result + source.hashCode();
            result = 31 * result + info.hashCode();
            return result;
        }
    }

    /**
     * Returns a graph of module dependences.
     *
     * Each Node represents a module and each edge is a dependence.
     * No analysis on "requires transitive".
     */
    public Graph<Node> moduleGraph() {
        Graph.Builder<Node> builder = new Graph.Builder<>();

        archives().stream()
            .forEach(m -> {
                Node u = new Node(m.getName(), Info.REQUIRES);
                builder.addNode(u);
                analyzer.requires(m)
                    .map(req -> new Node(req.getName(), Info.REQUIRES))
                    .forEach(v -> builder.addEdge(u, v));
            });
        return builder.build();
    }

    /**
     * Returns a graph of dependences.
     *
     * Each Node represents a class or package per the specified verbose level.
     * Each edge indicates
     */
    public Graph<Node> dependenceGraph() {
        Graph.Builder<Node> builder = new Graph.Builder<>();

        archives().stream()
            .map(analyzer.results::get)
            .filter(deps -> !deps.dependencies().isEmpty())
            .flatMap(deps -> deps.dependencies().stream())
            .forEach(d -> addEdge(builder, d));
        return builder.build();
    }

    private void addEdge(Graph.Builder<Node> builder, Analyzer.Dep dep) {
        Archive source = dep.originArchive();
        Archive target = dep.targetArchive();
        String pn = dep.target();
        if (verbose == CLASS || verbose == VERBOSE) {
            int i = dep.target().lastIndexOf('.');
            pn = i > 0 ? dep.target().substring(0, i) : "";
        }
        final Info info;
        Module targetModule = target.getModule();
        if (source == target) {
            info = Info.MODULE_PRIVATE;
        } else if (!targetModule.isNamed()) {
            info = Info.EXPORTED_API;
        } else if (targetModule.isExported(pn) && !targetModule.isJDKUnsupported()) {
            info = Info.EXPORTED_API;
        } else {
            Module module = target.getModule();
            if (module == Analyzer.REMOVED_JDK_INTERNALS) {
                info = Info.JDK_REMOVED_INTERNAL_API;
            } else if (!source.getModule().isJDK() && module.isJDK())
                info = Info.JDK_INTERNAL_API;
                // qualified exports or inaccessible
            else if (module.isExported(pn, source.getModule().name()))
                info = Info.QUALIFIED_EXPORTED_API;
            else
                info = Info.INTERNAL_API;
        }

        Node u = new Node(dep.origin(), source.getName(), info);
        Node v = new Node(dep.target(), target.getName(), info);
        builder.addEdge(u, v);
    }

}

com/sun/tools/jdeps/DepsAnalyzer.java

 

JDK 11 jdk.jdi.jmod - JDI Tool

JDK 11 jdk.jconsole.jmod - JConsole Tool

Download and Use JDK 11

⇑⇑ FAQ for JDK (Java Development Kit)

2020-07-07, 5281👍, 0💬